Satisfaction overview
(68 verified reviews)
Trusted by homeowners, strata communities, and businesses.
Impeccable safety record
/*prevent FOUC on mobile when using sidebar */
.dwc-mobile :is(.bricks-is-frontend.brx-header-left, .bricks-is-frontend.brx-header-right) #brx-header {
position: relative;
inline-size: 100%;
flex-direction: column;
}
.dwc-mobile .bricks-is-frontend:is(.brx-header-left, .brx-header-right) :is(#brx-content, #brx-footer) {
margin-inline-start: 0;
}
/*prevent FOUC on desktop when using sidebar */
.bricks-is-frontend:is(.brx-header-left, .brx-header-right):not(.show-nav) .dwc-nav-wrapper {
display: none;
}
/*=== sidebar css ===*/
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header {
flex-direction: column;
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.7);
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]).no-scroll {
overflow: visible;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
max-block-size: 100dvb;
padding-block-end: 12rem;
overscroll-behavior: contain;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nav-wrapper {
position: relative;
overflow: hidden;
block-size: 100%;
transform: translateX(0%);
visibility: visible;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) .dwc-nest-menu .brxe-toggle {
display: none !important;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu {
display: flex;
flex-direction: column;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-header > div {
display: flex;
grid-template-columns: 1fr;
block-size: 100%;
flex-direction: column;
justify-content: flex-start;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-menu-wrap {
inline-size: 100%;
display: grid;
grid-template-columns: 1fr;
block-size: 100%;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header :is(.brxe-code, .dwc-nest-menu-overlay) {
display: none;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-header {
inline-size: 100%;
padding-inline: 0;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu-top {
min-block-size: var(--top-offset);
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu:not( [data-hide-close-bar = 'true']) .brx-dropdown-content {
inset-block-start: calc(var(--top-offset) + 1px) !important;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu:not( [data-submenu-reveal = 'slide']) .brx-dropdown-content:not([data-submenu-reveal = 'slide'] *) {
inset-inline-start: 0;
inset-block-start: unset !important;
overflow: hidden;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu:not([data-submenu-reveal = 'slide']) .brxe-dropdown:not(.open.active) > .brx-dropdown-content > .brxe-dropdown:not([data-submenu-reveal = 'slide'] *){
visibility: hidden;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested.brx-open .brxe-dropdown > .brx-dropdown-content {
overscroll-behavior: contain;
min-inline-size: var(--mobile-menu-width);
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu .brxe-dropdown.open > .brx-submenu-toggle button:not([data-submenu-reveal = 'expand'] button) {
min-block-size: calc(var(--top-offset) - 1px);
inset-block-start: 0;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu .brxe-dropdown.open[data-submenu-reveal = 'slide'] > .brx-submenu-toggle button {
min-block-size: calc(var(--top-offset) - 1px);
inset-block-start: 0;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu .brxe-dropdown .brx-submenu-toggle button {
min-block-size: 0;
}
/* sidebar css ends*/
/*sidebar in builder*/
/*=== sidebar css ===*/
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header {
flex-direction: column;
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.7);
--top-offset: 40px;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
max-block-size: 100dvb;
padding-block-end: 12rem;
overscroll-behavior: contain;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nav-wrapper {
position: relative;
overflow: hidden;
block-size: 100%;
transform: translateX(0%);
visibility: visible;
}
body:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu .brxe-toggle {
display: none !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu {
display: flex;
flex-direction: column;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-header > div {
display: flex;
grid-template-columns: 1fr;
block-size: 100%;
flex-direction: column;
justify-content: flex-start;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-menu-wrap {
inline-size: 100%;
display: grid;
grid-template-columns: 1fr;
block-size: 100%;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-header {
inline-size: 100%;
padding-inline: 0;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu-top {
min-block-size: var(--top-offset);
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu .brx-dropdown-content {
inset-block-start: calc(var(--top-offset) - 1px) !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested.brx-open .brxe-dropdown > .brx-dropdown-content {
overscroll-behavior: contain;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu .brxe-dropdown.open > .brx-submenu-toggle button {
min-block-size: calc(var(--top-offset) - 1px);
inset-block-start: 0;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu .brxe-dropdown .brx-submenu-toggle button {
min-block-size: 0;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu {
margin: 0 !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .brx-nav-nested-items {
flex-direction: column !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-toggle--open.brxe-toggle {
display: flex !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu .brx-nav-nested-items {
position: relative !Important;
background: var(--mobile-menu-bg) !important;
align-items: stretch;
flex: 1;
}
:where(.brx-header-left, .brx-header-right)[data-builder-mode]:not(:has(.dwc-sidebar)) .dwc-nest-menu-top::before {
content: 'this space is the back text bar';
padding: 1rem;
background-color: gray;
color: white;
width: 100%;
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
letter-spacing: 1px;
}
/* MENU CTA (LAST BUTTON) */
:is(.brx-header-left, .brx-header-right)[data-builder-window] [data-last-item-is-button="true"].dwc-nest-menu .brx-nav-nested-items > .menu-item:last-of-type {
padding-inline: var(--menu-item-inline-padding) !important;
padding-block: var(--menu-item-block-padding) !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu-top {
min-block-size: 80px !important;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-nav-items {
overflow-y: scroll;
}
:is(.brx-header-left, .brx-header-right)[data-builder-mode] .brx-dropdown-content {
min-inline-size: var(--mobile-menu-width);
position: static;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
flex-wrap: nowrap;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu .brx-dropdown-content {
visibility: visible !important;
opacity: 1;
}
/*OVERLAY SIDEBAR*/
html:not(.dwc-mobile):has([data-overlay-sidebar=true]) {
--mobile-menu-bg: rgb(255 255 255 / 0%);
--menu-item-border: solid 1px rgb(255 255 255 / 50%);
}
html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) :is(main, footer){
margin: 0 !important
}
html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) :is(main, footer) :where(section):not(section>section) {
padding-inline-start: calc(var(--mobile-menu-width) + clamp(1.5rem, calc(0.625vw + 1.375rem), 1.875rem));
max-inline-size: 100%
}
html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) #brx-header {
border-radius: var(--overlay-sidebar-radius);
overflow: hidden;
background: var(--overlay-sidebar-bg);
box-shadow: var(--overlay-sidebar-shadow) !important;
inset: var(--overlay-sidebar-inset);
}
html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) .dwc-nest-header{
backdrop-filter: blur(13px);
background: transparent !important;
}
html:not(.dwc-mobile):has([data-overlay-sidebar=true]):not([data-builder-modee]) .brx-dropdown-content {
background-color: rgb(255 255 255 / 100%);
}
/*NO BRX-OPEN STYLES*/
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
display: flex;
flex-wrap: nowrap;
flex-direction: column !important;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) .dwc-nest-menu.brxe-nav-nested .brxe-dropdown .brx-dropdown-content {
visibility: visible;
min-inline-size: var(--mobile-menu-width) !important;
}
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) .dwc-nest-menu[data-submenu-reveal="expand"] .brxe-dropdown.open>.brx-dropdown-content {
position: static;
}
class SidebarNavigation {
constructor(options = {}) {
// Basic configuration properties
this.config = {
minWidth: options.minWidth || MegaMenuCONFIG.minWidth, // Using external minWidth variable
menuSelector: options.menuSelector || '.dwc-nest-menu',
openClass: options.openClass || 'brx-open',
activeClasses: options.activeClasses || ['open', 'active'],
leftHeaderClass: options.leftHeaderClass || 'brx-header-left',
rightHeaderClass: options.rightHeaderClass || 'brx-header-right',
debounceDelay: options.debounceDelay || 100,
menuItemClickDelay: options.menuItemClickDelay || 300
};
// Set dependent selectors
const menuSelector = this.config.menuSelector;
this.config.submenuToggleSelector = options.submenuToggleSelector || `${menuSelector} .brx-submenu-toggle`;
this.config.dropdownSelector = options.dropdownSelector || `${menuSelector} .brxe-dropdown`;
this.config.dropdownContentSelector = options.dropdownContentSelector || `${menuSelector} .brx-dropdown-content`;
// State
this.previousHeaderClass = null;
this.dropdownClickHandlers = new Map();
this.menuHoverHandlers = null;
this.menuItemClickTimeout = null;
this.keyboardNavHandler = null;
this.cachedFocusableElements = null;
this.cachedElements = {
menuElement: null,
navElement: null,
dropdowns: null,
dropdownToggles: null,
menuItems: null
};
// Bind methods to this instance
this.handleResize = this.debounce(this.handleMenu.bind(this), this.config.debounceDelay);
this.handleOutsideClick = this.handleOutsideClick.bind(this);
}
// Initialize everything - called once
init() {
// Wait for DOM to be fully loaded before attaching events
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
this.initAfterDOMLoaded();
}, { once: true });
} else {
this.initAfterDOMLoaded();
}
return this;
}
// Separate initialization method to run after DOM is loaded
initAfterDOMLoaded() {
// Cache DOM elements once
this.cacheElements();
// Setup resize event with passive flag
window.addEventListener('resize', this.handleResize, { passive: true });
// Setup mutation observer for critical class changes only
this.setupMutationObserver();
// Initial setup based on current screen size
this.handleMenu();
// Cache focusable elements once if header class is present
if (this.hasHeaderClass()) {
this.cacheFocusableElements();
this.setupMenuFocusNavigation();
}
}
// Cache all required DOM elements upfront
cacheElements() {
this.cachedElements.menuElement = document.querySelector(this.config.menuSelector);
if (this.cachedElements.menuElement) {
this.cachedElements.navElement = this.cachedElements.menuElement.querySelector('.dwc-nest-nav-items');
this.cachedElements.dropdowns = Array.from(document.querySelectorAll(this.config.dropdownSelector));
this.cachedElements.dropdownToggles = Array.from(document.querySelectorAll(this.config.submenuToggleSelector));
this.cachedElements.menuItems = Array.from(document.querySelectorAll(`${this.config.menuSelector} .menu-item`));
}
}
// Set up a focused mutation observer only for dropdown state changes
setupMutationObserver() {
if (!this.cachedElements.dropdowns || this.cachedElements.dropdowns.length === 0) return;
const callback = (mutations) => {
for (let mutation of mutations) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const target = mutation.target;
const prevClassList = mutation.oldValue ? mutation.oldValue.split(' ') : [];
const hadBothBefore = prevClassList.includes('open') && prevClassList.includes('active');
const hasBothNow = target.classList.contains('open') && target.classList.contains('active');
if (hadBothBefore !== hasBothNow) {
this.updateDropdownAccessibility();
break; // Only need to update once per batch
}
}
}
};
// Create observer with optimized options
this.classObserver = new MutationObserver(callback);
// Observe only the dropdown elements
this.cachedElements.dropdowns.forEach(dropdown => {
this.classObserver.observe(dropdown, {
attributes: true,
attributeFilter: ['class'],
attributeOldValue: true
});
});
}
// Cache focusable elements for keyboard navigation
cacheFocusableElements() {
if (!this.cachedElements.navElement) return;
// Get direct children of nav
const directChildren = Array.from(this.cachedElements.navElement.children);
// Find the first focusable element within each direct child
this.cachedFocusableElements = directChildren.map(child => {
// Check if the child itself is focusable
if (child.matches('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])')) {
return child;
}
// Otherwise, find the first focusable element within this child
return child.querySelector('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
}).filter(Boolean); // Remove null/undefined values
}
// Clean up all event listeners and observers
destroy() {
// Clean up the mutation observer
if (this.classObserver) {
this.classObserver.disconnect();
this.classObserver = null;
}
// Clean up resize listener
window.removeEventListener('resize', this.handleResize);
// Clean up click handlers
if (this.dropdownClickHandlers.size > 0) {
this.dropdownClickHandlers.forEach((handler, toggle) => {
toggle.removeEventListener('click', handler);
});
this.dropdownClickHandlers.clear();
}
// Clean up hover handlers
this.cleanupMenuHover();
// Clean up menu item click handlers
this.cleanupMenuItemClicks();
// Clean up outside click handler
document.removeEventListener('click', this.handleOutsideClick);
// Clean up keyboard navigation
if (this.keyboardNavHandler) {
document.removeEventListener('keydown', this.keyboardNavHandler);
this.keyboardNavHandler = null;
}
// Clear any pending timeouts
if (this.menuItemClickTimeout) {
clearTimeout(this.menuItemClickTimeout);
this.menuItemClickTimeout = null;
}
}
// Utility methods
hasHeaderClass() {
return document.body.classList.contains(this.config.leftHeaderClass) ||
document.body.classList.contains(this.config.rightHeaderClass);
}
debounce(func, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => func(...args), delay);
};
}
// Check if an element has all the required active classes
hasAllActiveClasses(element) {
return this.config.activeClasses.every(className => element.classList.contains(className));
}
// Toggle all active classes on an element
toggleActiveClasses(element) {
this.config.activeClasses.forEach(className => {
element.classList.toggle(className);
});
}
// Core functionality methods
handleMenu() {
if (!this.cachedElements.menuElement) return;
if (!this.hasHeaderClass() && !this.previousHeaderClass) return;
const screenWidth = window.innerWidth;
const isLargeScreen = screenWidth >= this.config.minWidth;
const menuElement = this.cachedElements.menuElement;
if (!isLargeScreen) {
// Save which class was present before removal
if (this.hasHeaderClass()) {
this.previousHeaderClass = document.body.classList.contains(this.config.leftHeaderClass)
? this.config.leftHeaderClass
: this.config.rightHeaderClass;
// Remove header classes
document.body.classList.remove(this.config.leftHeaderClass, this.config.rightHeaderClass);
menuElement.classList.remove(this.config.openClass);
// Reset accessibility attributes
this.resetAccessibilityAttributes();
}
// Clean up event handlers for mobile view
this.cleanupMenuHover();
this.cleanupMenuItemClicks();
this.cleanupDropdownHandlers();
document.removeEventListener('click', this.handleOutsideClick);
return;
}
// Large screen behavior
if (!this.hasHeaderClass() && this.previousHeaderClass) {
document.body.classList.add(this.previousHeaderClass);
}
if (this.hasHeaderClass()) {
if (!menuElement.classList.contains(this.config.openClass)) {
menuElement.classList.add(this.config.openClass);
}
// Setup elements for large screen view
this.setupMenuHover();
this.setupMenuItemClicks();
this.setupDropdownHandlers();
this.setupMenuFocusNavigation();
this.updateDropdownAccessibility();
// Ensure outside click handler is set up
document.removeEventListener('click', this.handleOutsideClick);
document.addEventListener('click', this.handleOutsideClick, { passive: false });
}
}
// Reset accessibility attributes when switching to mobile
resetAccessibilityAttributes() {
if (!this.cachedElements.dropdowns) return;
// Remove all inert attributes from dropdown contents
this.cachedElements.dropdowns.forEach(dropdown => {
const content = dropdown.querySelector(this.config.dropdownContentSelector);
if (content) {
content.removeAttribute('inert');
}
const button = dropdown.querySelector('button');
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
}
setupMenuFocusNavigation() {
// Only run if hasHeaderClass() is true and we have focusable elements
if (!this.hasHeaderClass() || !this.cachedFocusableElements || this.cachedFocusableElements.length === 0) {
return;
}
// Clean up previous handler if it exists
if (this.keyboardNavHandler) {
document.removeEventListener('keydown', this.keyboardNavHandler, true);
this.keyboardNavHandler = null;
}
const navMenu = this.cachedElements.menuElement;
const focusableElements = this.cachedFocusableElements;
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length - 1];
// Find adjacent focusable elements outside the menu (only once during setup)
const headerElement = navMenu.closest('header') || document.querySelector('header');
// Prepare variables to hold adjacent elements
let prevFocusableElement = null;
let nextFocusableElement = null;
let firstElementAfterHeader = null;
if (headerElement) {
// Get all focusable elements within the header - do this once and cache the result
const headerFocusables = Array.from(
headerElement.querySelectorAll('a:not([tabindex="-1"]), button:not([tabindex="-1"]), input:not([tabindex="-1"]), select:not([tabindex="-1"]), textarea:not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])')
).filter(el => window.getComputedStyle(el).display !== 'none');
// Find the index of our first and last menu elements in one pass
const menuStartIndex = headerFocusables.indexOf(firstFocusableElement);
const menuEndIndex = headerFocusables.indexOf(lastFocusableElement);
// Cache the adjacent elements
if (menuStartIndex > 0) {
prevFocusableElement = headerFocusables[menuStartIndex - 1];
}
if (menuEndIndex !== -1 && menuEndIndex < headerFocusables.length - 1) {
nextFocusableElement = headerFocusables[menuEndIndex + 1];
}
// Pre-calculate the first element after header - but only if needed
if (!nextFocusableElement) {
// Use a more efficient selector that targets immediate children of body that aren't the header
const selector = 'body > *:not(header)';
const nonHeaderElements = document.querySelectorAll(selector);
// Only process if we have elements
if (nonHeaderElements.length > 0) {
// Create a function to find the first focusable element (used later if needed)
this.findFirstFocusableAfterHeader = () => {
for (const element of nonHeaderElements) {
const focusable = element.querySelector('a:not([tabindex="-1"]), button:not([tabindex="-1"]), input:not([tabindex="-1"]), select:not([tabindex="-1"]), textarea:not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])');
if (focusable && window.getComputedStyle(focusable).display !== 'none') {
return focusable;
}
}
return null;
};
}
}
}
// Create keyboard navigation handler with closure over the cached elements
this.keyboardNavHandler = (e) => {
// Quick check for Tab key first
if (e.key !== 'Tab') return;
// Then check if focus is inside the menu
if (!navMenu.contains(document.activeElement)) return;
let targetElement = null;
// Handle tab navigation at boundaries only
if (!e.shiftKey && document.activeElement === lastFocusableElement) {
// Forward tab from last element
e.preventDefault();
e.stopPropagation();
if (nextFocusableElement) {
targetElement = nextFocusableElement;
} else if (this.findFirstFocusableAfterHeader) {
// Only search for elements after header if needed and not already found
firstElementAfterHeader = this.findFirstFocusableAfterHeader();
targetElement = firstElementAfterHeader;
}
// Focus on the target or body as fallback
setTimeout(() => {
if (targetElement) {
targetElement.focus();
} else {
document.body.setAttribute('tabindex', '-1');
document.body.focus();
document.body.removeAttribute('tabindex');
}
}, 10);
}
else if (e.shiftKey && document.activeElement === firstFocusableElement) {
// Backward tab from first element
e.preventDefault();
e.stopPropagation();
setTimeout(() => {
if (prevFocusableElement) {
prevFocusableElement.focus();
} else {
document.body.setAttribute('tabindex', '-1');
document.body.focus();
document.body.removeAttribute('tabindex');
}
}, 10);
}
};
// Use capture phase for the event
document.addEventListener('keydown', this.keyboardNavHandler, true);
}
setupMenuHover() {
const menuElement = this.cachedElements.menuElement;
if (!menuElement) return;
// Clean up existing hover handlers first
this.cleanupMenuHover();
// Create event handlers
const mouseenterHandler = () => {
menuElement.classList.add(this.config.openClass);
};
const mouseleaveHandler = () => {
menuElement.classList.remove(this.config.openClass);
};
// Add event listeners with passive flag for better performance
menuElement.addEventListener('mouseenter', mouseenterHandler, { passive: true });
menuElement.addEventListener('mouseleave', mouseleaveHandler, { passive: true });
// Store the handlers for cleanup
this.menuHoverHandlers = {
element: menuElement,
mouseenter: mouseenterHandler,
mouseleave: mouseleaveHandler
};
}
cleanupMenuHover() {
if (this.menuHoverHandlers) {
const { element, mouseenter, mouseleave } = this.menuHoverHandlers;
element.removeEventListener('mouseenter', mouseenter);
element.removeEventListener('mouseleave', mouseleave);
this.menuHoverHandlers = null;
}
}
setupMenuItemClicks() {
if (!this.cachedElements.menuItems || this.cachedElements.menuItems.length === 0) return;
// Clean up existing handlers first
this.cleanupMenuItemClicks();
const menuElement = this.cachedElements.menuElement;
const menuItemHandlers = new Map();
this.cachedElements.menuItems.forEach(item => {
const clickHandler = () => {
if (this.hasHeaderClass()) {
// Clear any existing timeout
if (this.menuItemClickTimeout) {
clearTimeout(this.menuItemClickTimeout);
}
// Set timeout before adding the class
this.menuItemClickTimeout = setTimeout(() => {
if (!menuElement.classList.contains(this.config.openClass)) {
menuElement.classList.add(this.config.openClass);
}
}, this.config.menuItemClickDelay);
}
};
menuItemHandlers.set(item, clickHandler);
item.addEventListener('click', clickHandler);
});
this.menuItemClickHandlers = menuItemHandlers;
}
cleanupMenuItemClicks() {
if (this.menuItemClickHandlers && this.menuItemClickHandlers instanceof Map) {
this.menuItemClickHandlers.forEach((handler, item) => {
item.removeEventListener('click', handler);
});
this.menuItemClickHandlers.clear();
}
if (this.menuItemClickTimeout) {
clearTimeout(this.menuItemClickTimeout);
this.menuItemClickTimeout = null;
}
}
setupDropdownHandlers() {
if (!this.hasHeaderClass() || !this.cachedElements.dropdownToggles) return;
// Clean up existing handlers first
this.cleanupDropdownHandlers();
this.cachedElements.dropdownToggles.forEach(toggle => {
const clickHandler = (event) => {
event.stopPropagation();
event.preventDefault();
const dropdown = toggle.closest(this.config.dropdownSelector);
if (dropdown) {
this.toggleActiveClasses(dropdown);
this.updateDropdownAccessibility();
}
};
this.dropdownClickHandlers.set(toggle, clickHandler);
toggle.addEventListener('click', clickHandler);
});
}
cleanupDropdownHandlers() {
if (this.dropdownClickHandlers.size > 0) {
this.dropdownClickHandlers.forEach((handler, toggle) => {
toggle.removeEventListener('click', handler);
});
this.dropdownClickHandlers.clear();
}
}
handleOutsideClick(event) {
if (event.target.tagName === 'A') return;
if (!event.target.closest(this.config.dropdownSelector)) return;
if (!event.target.closest(this.config.submenuToggleSelector)) {
event.preventDefault();
event.stopPropagation();
}
}
updateDropdownAccessibility() {
// Only run if hasHeaderClass() is true
if (!this.hasHeaderClass() || !this.cachedElements.dropdowns) return;
this.cachedElements.dropdowns.forEach(dropdown => {
const content = dropdown.querySelector(this.config.dropdownContentSelector);
const button = dropdown.querySelector('button');
// Check if dropdown has all active classes
const isOpen = this.hasAllActiveClasses(dropdown);
if (content) {
if (isOpen) {
content.removeAttribute('inert');
} else {
content.setAttribute('inert', '');
}
}
if (button) {
button.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
}
});
}
}
const sidebarNav = new SidebarNavigation().init();Fort Langley construction services
VALROC Development Ltd. provides practical, well-executed construction services for property owners in and around Fort Langley, BC. While our work here has focused on core infrastructure improvements, our broader Metro Vancouver experience allows us to deliver reliable results with respect for the area’s unique character.
Customer confidence
Fort Langley projects benefit from planning that respects established properties, village activity, heritage context, Township requirements, and limited staging.
(68 verified reviews)
Trusted by homeowners, strata communities, and businesses.
Impeccable safety record
Fort Langley includes established homes, active commercial areas, and properties where heritage character, access, neighbours, and limited staging deserve early attention. We review those conditions before work is sequenced.
Customers gain a coordinated plan connecting the intended result with Township questions, equipment, materials, site protection, and construction logistics.
Local construction planning
Construction planning in Fort Langley starts with the property, the municipal jurisdiction, and the practical conditions that affect approvals, access, sequencing, equipment, and material movement.
CONSTRUCTION SERVICE DIRECTORY
Open the complete construction service hub, choose a service category, or go directly to a core service.
Decisions before construction
A site conversation can identify alternatives before costs are committed, particularly where existing buildings, neighbouring properties, street or lane access, staging space, and the character of the site affect the plan.
Review existing buildings, neighbouring properties, street or lane access, staging space, and the character of the site in relation to the result you want and the equipment or material movement the work may require.
Identify likely Township building, demolition, and development-planning requirements, utility-locate responses, disposal requirements, and property-specific questions before finalizing the sequence.
Coordinate crews, deliveries, occupied areas, hauling, and site protection so the construction sequence reflects how this Fort Langley property is actually used.
A practical route forward
The exact sequence depends on the work and property. Early review of Township of Langley requirements, access, disposal, equipment, and customer priorities helps turn an idea into a coordinated plan.
Identify likely Township of Langley permits, heritage or property considerations, utility locates, disposal needs, and technical details.
Plan crews, equipment, deliveries, hauling, noise, protection, and staging around the property and surrounding activity.
Complete the agreed work in sequence, review important site and finish details, and provide a clear customer handoff.
Discuss the intended result, existing buildings, access, neighbours, village activity, drainage, and available working space.
What customers gain from the way we work
These advantages help customers evaluate more than a price, including project clarity, relevant experience, site coordination, in-house capability, and the way disruption will be managed.
Our contracts eliminate guesswork with clearly defined terms, pricing, timelines, and warranties, ensuring total transparency and peace of mind.
We respect your time and space, ensuring efficient construction with minimal disruptions to your home or business.
With a strong portfolio of completed work, our experience ensures high-quality craftsmanship and efficient project execution.
Our reputation is built on trust, industry recognition, and strong professional relationships, ensuring confidence in every project we take on.
In-house capability
Our Langley yard provides a base for selecting and staging equipment for Fort Langley projects around access, excavation depth, hauling, material movement, compaction, and the actual scope of work.

Excavation fleet
Our in-house range includes compact machines for tight access, mid-size excavators for precise residential work, larger Deere excavators for deeper excavation and material handling, plus hydraulic breaker capability for concrete and rock removal.

Heavy Machinery & Earthmoving Equipment
Delivers smooth, even asphalt and soil compaction, improving surface durability and road longevity.

Mobile Construction Equipped Service Vehicles
Facilitates equipment and material transport, allowing us to move multiple machines and long materials efficiently.

Heavy Machinery & Earthmoving Equipment
A compact, maneuverable track dumper that allows us to transport materials through tight spaces, improving site logistics and reducing manual labour.

Heavy Machinery & Earthmoving Equipment
A high-capacity hauler for transporting materials, debris, and equipment, streamlining job site cleanup and logistics.

Mobile Construction Equipped Service Vehicles
Our fully equipped mobile service truck, essential for transporting contracting tools, materials, and heavy-duty equipment, ensuring on-site readiness and maximum efficiency.

Heavy Machinery & Earthmoving Equipment
A compact excavator with strong digging power, perfect for tight job sites requiring precision excavation.
Experience from local customers
Relevant experiences are presented as readable, image-led stories. Open a review only when you want the full detail.


When we first met with Tony, there was more to the project than a cracked driveway and aging retaining walls. He had a vision of creating a front entrance that was more functional, more inviting, and better suited to his family’s long-term needs. At the same time, there were underlying concerns with water penetration, drainage, and infrastructure that couldn’t be ignored.

“The best construction projects don’t just fix what’s broken, they uncover opportunities to improve the entire property.”
In Tony’s case, what began as concerns over a deteriorating driveway and failing retaining walls became an opportunity to address several interconnected property issues at the same time. By developing a coordinated plan, we were able to improve drainage, help protect the home’s foundation from ongoing water penetration, enhance the functionality of the property, create a more welcoming front entrance, and increase long-term property value.
Rather than approaching each concern as a separate project, the goal was to make every improvement work together. The result was a property that not only looks better but performs better for the homeowner and their family.
One of the most rewarding parts of our work is collaborating with homeowners who want to make thoughtful investments in their property. Through consultation and on-site discussions, we explored how multiple improvements could work together, enhancing curb appeal while addressing water management, protecting the foundation, and improving the overall performance of the property.
For many homeowners, construction is about more than fixing a single problem. It’s an opportunity to improve the way a property functions, increase its value, and create something that can be enjoyed for years to come. Tony’s project is a great example of what can happen when a clear vision is combined with careful planning and a coordinated approach to construction.
The following testimonial reflects that journey and the relationship we’ve built together over four successful projects.
Hi, I’m Tony from the Brookswood Township of Langley.
We were hoping to solve primarily the water problems going into the garage and the downspout on the far side of the house. It was puddling. Some of it was going into the crawl space, so we were hoping to alleviate that, which we did.
I didn’t want to have too many contractors on site. I wanted it to be one contractor facility, and the whole job, and completing the whole job, and that’s what happened.
A job like this, they all tie into each other at one point or another, and it’s imperative that you have somebody that knows what they’re doing in every facet of the work.
I didn’t realize how complex it was going to be, and in the end, it really surprised me how well it was actually done and how well it actually works.
The team communicates, they have a good system, and it shows because they get the end result, and they get it fast. It gets done fast.
I could be on site. I could have questions on site, and I had no problems getting an immediate response, which was reassuring.



I was able to have a visual on how this all works, how the system works, and ultimately could see it firsthand. It reassured me that everything was going smoothly and it was going to work in the end.
The wall, for me, is a real beauty, the way it was done. There’s a nice curve to it. It gives us more space. It’s very durable, very, very functional. I have confidence in it that it’s strong. That’s what counts with me.
I would definitely recommend VALROC to others. Simply put, the quality of workmanship is extremely high.
A loyal crew, they work hard. They’re organized. They leave a clean site. All the above.
When dealing with VALROC, they treat their project like it’s their own house, and I think that shows in their work.
You can’t say that this would not be a good investment. It’s one of those situations where it adds function, it adds to the aesthetics, so I’m very pleased with it.

We’ve done multiple different projects, and I know that they have a depth of knowledge in different areas of construction that are very, very beneficial.
It added more space for us to walk through, and then the driveway will have drainage leading to the actual drainage, so it works. It’s much better than it used to be, for sure.
★★★★★
Looking Beyond the Project, Finding Hidden Opportunities Every Home in Brookswood, Langley Has a Story When we first met with Tony, there was more to the project than a cracked driveway and aging retaining walls. He had a vision of creating a front entrance that was more functional, more inviting, and better suited to his…
High-value planning information
Verified municipal, utility, recycling, and disposal contacts for construction decisions in Fort Langley. Use each section for a focused task, then confirm current requirements with the authority before acting.

Check Township building requirements, Start with Township permit, inspection, and application guidance.
Contact: buildinginfo@tol.ca · 604-533-6018
Before you proceed: Confirm the property is within the Township and identify the permit type first. A clear scope and property information can prevent an application entering the wrong review stream.
Review Township demolition requirements, Check requirements before removing a building or structure.
Contact: buildinginfo@tol.ca · 604-533-6018
Before you proceed: Hazardous-material, utility, and waste steps may be prerequisites. Sequence prerequisites before booking demolition.
Review Township planning and zoning requirements, Check zoning and development conditions that may affect the property.
Contact: cdinfo@tol.ca · 604-533-6034
Before you proceed: Property-specific zoning and area-plan requirements may apply. Review planning constraints before finalizing access or project scope.
Request a free utility locate, Request utility-owner information before digging or excavation.
Contact: info@bc1c.ca · 1-800-474-6886
Before you proceed: A locate request does not identify every privately owned line; review the response package before work starts. Allow time for members to respond and keep the ticket information available on site.
Find a facility for a specific material, Search for facilities that accept a specific construction, renovation, or landscaping material.
Contact: 604-732-9253
Before you proceed: Confirm the facility accepts the material type and load source before travelling. Use this directory when the material is not accepted at the nearest municipal or regional facility.
Check accepted materials at the Langley facility, Confirm whether the regional facility accepts the project material.
Contact: 604-856-3225
Before you proceed: Check accepted materials, fees, hours, and load rules before hauling. Separating materials may preserve recycling options and reduce disposal cost.
Review asbestos requirements before disturbing materials, Understand asbestos identification, qualified-person, and safe-work requirements before renovation or demolition.
Before you proceed: Suspect materials must be assessed before they are disturbed; disposal facilities may require documentation. Older buildings can contain asbestos in products that are not obvious from appearance alone.
Check provincial hazardous-waste requirements, Find provincial guidance for hazardous waste that cannot enter ordinary construction-waste streams.
Before you proceed: Use an authorized pathway; facility rules and documentation vary by material. Confirm classification and receiving requirements before material is transported.
Common local questions
Open only the answer you need. These questions remain connected through the existing Location relationship.
If you are constructing a new driveway in Fort Langley, a permit is typically required. However, if you are repairing or replacing an existing driveway without altering its size or location, you may not need a permit. The Township of Langley Engineering Department oversees driveway regulations, and approvals may be needed depending on road classification and zoning restrictions.
At Valroc Development Ltd., we have extensive experience navigating the permitting process and can assist in determining whether a permit is necessary for your project. We can handle the application on your behalf to save you time and ensure compliance with local regulations.
For official guidelines, contact the Township of Langley Engineering Department or reach out to us for a free on-site consultation.
If you are constructing a new driveway in Fort Langley, a permit is typically required. However, if you are repairing or replacing an existing driveway without altering its size or location, you may not need a permit. The Township of Langley Engineering Department oversees driveway regulations, and approvals may be needed depending on road classification and zoning restrictions.
At Valroc Development Ltd., we have extensive experience navigating the permitting process and can assist in determining whether a permit is necessary for your project. We can handle the application on your behalf to save you time and ensure compliance with local regulations.
For official guidelines, contact the Township of Langley Engineering Department or reach out to us for a free on-site consultation.
Fort Langley is a historic community with unique construction needs. Valroc Development Ltd. has successfully completed projects including:
We have built custom homes designed to match Fort Langley’s distinct architectural character, including heritage-inspired residences and modern builds with premium finishes.
We specialize in stamped, exposed aggregate, and broom-finished concrete surfaces for residential and commercial properties, ensuring durability and aesthetic appeal.
From foundation digs to land clearing and grading, we provide full excavation services to prepare sites for new developments or property improvements.
Our team provides asphalt paving solutions for residential, commercial, and strata properties, including private roadways, parking lots, and pathways.
Water management is critical in Fort Langley. We have installed and repaired perimeter drainage systems, drain tiles, and stormwater management solutions to prevent flooding and structural damage.
Whether you need a detached garage, carport, or a fully customized workshop, we provide complete design and build solutions tailored to your needs.
If you’re planning a construction project in Fort Langley, contact us for a free estimate!
Fort Langley is a historic community with unique construction needs. Valroc Development Ltd. has successfully completed projects including:
We have built custom homes designed to match Fort Langley’s distinct architectural character, including heritage-inspired residences and modern builds with premium finishes.
We specialize in stamped, exposed aggregate, and broom-finished concrete surfaces for residential and commercial properties, ensuring durability and aesthetic appeal.
From foundation digs to land clearing and grading, we provide full excavation services to prepare sites for new developments or property improvements.
Our team provides asphalt paving solutions for residential, commercial, and strata properties, including private roadways, parking lots, and pathways.
Water management is critical in Fort Langley. We have installed and repaired perimeter drainage systems, drain tiles, and stormwater management solutions to prevent flooding and structural damage.
Whether you need a detached garage, carport, or a fully customized workshop, we provide complete design and build solutions tailored to your needs.
If you’re planning a construction project in Fort Langley, contact us for a free estimate!
Fort Langley has strict zoning regulations to maintain its historic charm while accommodating modern development. Navigating these bylaws and zoning requirements can be complex, but our team at Valroc Development Ltd. has experience working with the Township of Langley’s Planning and Development Department to ensure projects meet local building codes and heritage preservation requirements.
We assist with:
Fort Langley has strict zoning regulations to maintain its historic charm while accommodating modern development. Navigating these bylaws and zoning requirements can be complex, but our team at Valroc Development Ltd. has experience working with the Township of Langley’s Planning and Development Department to ensure projects meet local building codes and heritage preservation requirements.
We assist with:
Permit applications for building, driveway installations, home additions, and zoning variances can be accessed through the Township of Langley’s official website. You can also contact the Planning & Development Department directly for zoning details, site-specific requirements, and historical property modifications.
Instead of navigating this process alone, Valroc Development Ltd. can assist with gathering necessary documentation, preparing applications, and coordinating approvals to streamline your project timeline.
Permit applications for building, driveway installations, home additions, and zoning variances can be accessed through the Township of Langley’s official website. You can also contact the Planning & Development Department directly for zoning details, site-specific requirements, and historical property modifications.
Instead of navigating this process alone, Valroc Development Ltd. can assist with gathering necessary documentation, preparing applications, and coordinating approvals to streamline your project timeline.
Proper preparation can help ensure a smooth construction process. We recommend:
Proper preparation can help ensure a smooth construction process. We recommend:
Hiring the right contractor is critical for a successful project. Look for:
Valroc Development Ltd. has a proven track record of delivering high-quality projects in Fort Langley. Contact us to learn how we can bring your vision to life with trusted expertise and seamless project management.
Hiring the right contractor is critical for a successful project. Look for:
Valroc Development Ltd. has a proven track record of delivering high-quality projects in Fort Langley. Contact us to learn how we can bring your vision to life with trusted expertise and seamless project management.
We offer free on-site consultations to discuss your construction needs. Whether you’re planning a new build, renovation, or infrastructure upgrade, Valroc Development Ltd. is here to help.
📞 Call us today or request an estimate online!
We offer free on-site consultations to discuss your construction needs. Whether you’re planning a new build, renovation, or infrastructure upgrade, Valroc Development Ltd. is here to help.
📞 Call us today or request an estimate online!