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();Langley construction services
Serving the Township and City of Langley with full-scope construction expertise, VALROC delivers residential, strata, and commercial projects backed by over a decade of hands-on experience, centralized operations, and proven execution across every stage of construction.
Customer confidence
Our Langley construction yard supports local equipment staging, material handling, crew coordination, and practical planning for both City and Township properties.
(68 verified reviews)
Trusted by homeowners, strata communities, and businesses.
Impeccable safety record
Langley includes compact urban properties, growing neighbourhoods, rural acreages, and larger sites with very different access and servicing conditions. Our local operating base helps us assess equipment, materials, crews, and mobilization around the actual property.
Customers benefit from early conversations about jurisdiction, access, drainage, staging, and the combination of services their project may require.
Local construction knowledge
Planning construction in Langley starts with the property, the municipality, and the practical conditions that affect access, sequencing, permits, 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 practical alternatives before costs are committed, especially where access, drainage, neighbouring properties, occupied spaces, or municipal requirements affect the plan.
Review the intended result, property constraints, equipment access, grades, drainage, and whether a simpler construction approach could meet the goal.
Confirm whether the property is in the City of Langley or Township of Langley, then identify likely permit, zoning, utility-locate, conservation, or disposal requirements.
Plan sequencing, material handling, parking, occupied areas, and crew access to reduce disruption and avoid doing the same work twice.
A practical route from idea to construction
The exact sequence depends on the work and the property. These four conversations help turn an early idea into a coordinated plan without pretending every site follows the same checklist.
Define the work, likely permits, utility locates, disposal needs, technical details, and any City or Township requirements.
Plan crews, machinery, materials, deliveries, hauling, site protection, and a sequence suited to the property.
Complete the work, review important details on site, address the agreed scope, and leave the customer with a clear handoff.
Discuss the result you want, existing conditions, access, drainage, neighbouring properties, and the priorities that matter most.
What customers gain from the way we work
These are practical advantages customers can evaluate before hiring us, from clear project expectations to in-house equipment and experience built across many types of construction work.
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.
We respect your time and space, ensuring efficient construction with minimal disruptions to your home or business.
Our extensive fleet of heavy-duty machinery, mobile service trucks, and specialized tools ensures unmatched efficiency and precision on every job site.
In-house capability
Our Langley yard gives us a practical base for selecting and staging equipment around access, excavation depth, 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.

So we bought the house three years ago and had some settling issues in the front entrance that we notice when we bought it the side of the house had separated and dropped from the house 6/8 inches on the low side and 4 inches up the front of the house. In the three years that we’ve been here, we noticed a bit more separation on it and for the last year, I’ve been calling around trying to find someone you know they can come in. We were focussed more on the front of the house because the driveway is in decent shape, but after talking to a few people and after talking to Dominic at VARLOC, we went with just replacing everything. In hindsight, looking at the material that was. It was built no rebar. We are pretty happy with that decision.

I called Dominic, they were doing a project close to our house. Everybody got back to us really fast, and our questions got answered quickly, Domenic came over gave us an estimate. I think it was like three days, that we got our quote back I had a couple of questions I called Dominic. He answered the questions no problem and then as far as scheduling and contract, we agreed to it and so getting this project done was pretty easy.

I’m a stickler clean job sites. I’ve worked in construction. I’ve worked at BC Hydro for a number of years. They left the job site, clean and tidy you could tell that they cared and was quite happy.
I think our house looks really beautiful and it’s added a lot of curb appeal to it. I wasn’t expecting it to make that much of a difference but it does so I’m really happy with the outcome. I think the texture is perfect and exactly what we wanted.
I would highly recommend VALROC, they started every day at 7, punctual and efficient.



★★★★★
So we bought the house three years ago and had some settling issues in the front entrance that we notice when we bought it the side of the house had separated and dropped from the house 6/8 inches on the low side and 4 inches up the front of the house. In the three years…

My name is Michelle Ling. I’ve lived in Langley for approximately three years.
What I was hoping for was mainly access to the backyard. I wanted a nice big platform for the kids to play on and also I have elderly parents. I was concerned about being able to get them in and out of the home so the driveway has accomplished that.
There was a gate, hedges and boulders along the side of the house , Valroc came in. They took all that material away, set us up for a concrete did the concrete pour and because of the different elevations of the driveway they also built a retaining wall from the top of the property to the bottom.
To be honest, I found Valroc online like everybody nowadays I’ve reached out to a couple of other people and got a couple of quotes. Valroc, in my opinion, felt the most comfortable was the most professional. In the time that I dealt with with the Valroc Team, you guys came on time, you showed lots of respect for the property, and for my family. Little things that we noticed when the trucks pulled in, you guys put tarps underneath so that it didn’t drip ointo the driveway, one of the days you guys power washed a huge portion of the driveway. It was a great working environment when we had questions and concerns they were addressed. There’s been a couple of tiny little things, we called, somebody comes and they help us out. It’s been great.



When we were installing, we were fighting for space and talking back-and-forth between the neighbours Valroc and the team were able to come together with the neighbours and myself because that relationship is important to me and we were able to come to a resolution together. The end result, I think that the recommendations made by the team have resulted in a more useable functional driveway so we’ve been very happy.
There’s a bunch of boulders and extra material either had to get taken away or repurposed in fact the garden that we had in the back was positioned in the way that would’ve taken over some of the space that was designated for the driveway pad and your team came in and actually move the garden for us. Place some of the rocks in boulders within the garden. Now we have a new functional garden.
I think the end finish result has definitely accomplished what we were hoping for, overall it’s been a great project in terms of the build, I can say both myself, and my neighbour who has has a building background when they were watching the stuff put in, they were very impressed with how it was all set up, the materials, how it was put together and the details in some of the works like the bevelled edges. I would recommend Valroc, courteous, aways on time and most importantly the estimate that was provided to us is what I paid in the end.
★★★★★
My name is Michelle Ling. I’ve lived in Langley for approximately three years. What I was hoping for was mainly access to the backyard. I wanted a nice big platform for the kids to play on and also I have elderly parents. I was concerned about being able to get them in and out of…
High-value planning information
Verified municipal, utility, recycling, and disposal contacts for construction decisions in Langley. Use each section for a focused task, then confirm current requirements with the authority before acting.

Confirm the municipality first: a Langley property may be in the City of Langley or the Township of Langley. Each has a separate permit and planning process.
Building-permit, inspection, and application guidance for Township properties.
Contact: buildinginfo@tol.ca · 604-533-6018
Confirm the property is in the Township and identify the permit type before applying.
Requirements to review before removing a building or structure.
Contact: buildinginfo@tol.ca · 604-533-6018
Hazardous-material, utility, and waste steps may be prerequisites.
Building and demolition permit information for properties inside Langley City.
Contact: inspections@langleycity.ca · 604-514-2804
Planning and development guidance for a Langley City property.
Contact: planning@langleycity.ca · 604-514-2830
Township zoning, development conditions, and property-specific planning requirements.
Contact: cdinfo@tol.ca · 604-533-6034
Request information from participating utility owners before excavation or ground disturbance.
Contact: info@bc1c.ca · 1-800-474-6886
A locate request does not identify every privately owned line. Allow time for members to respond, review the response package, and keep the ticket information available on site.
Search by material and location for facilities accepting construction, renovation, landscaping, concrete, asphalt, wood, organics, and other recoverable materials.
Contact: 604-732-9253
Confirm the facility accepts the material type and load source before travelling. Separating materials may preserve recycling options and reduce disposal costs.
Regional recycling and waste drop-off at 1070–272 Street, Township of Langley.
Contact: 604-856-3225
Check accepted materials, fees, hours, and load rules before hauling.
Requirements for identifying and safely managing suspect asbestos-containing materials before renovation or demolition.
Suspect materials must be assessed before disturbance, and receiving facilities may require documentation.
Provincial guidance for hazardous materials that cannot enter ordinary construction-waste streams.
Confirm classification, documentation, transporter, and receiving-facility requirements before material is moved.
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 Langley, you may require a permit depending on the project’s scope. Typically, driveway permits are required for new installations or significant modifications, especially if the work impacts sidewalks, curbs, or municipal infrastructure. However, if you are repairing or replacing an existing driveway with the same dimensions and location, a permit may not be necessary. To avoid unnecessary delays, we recommend contacting VALROC Development Ltd. for an expert assessment. We handle the entire process, including determining permit requirements and working with local authorities to streamline approvals.
If you are constructing a new driveway in Langley, you may require a permit depending on the project’s scope. Typically, driveway permits are required for new installations or significant modifications, especially if the work impacts sidewalks, curbs, or municipal infrastructure. However, if you are repairing or replacing an existing driveway with the same dimensions and location, a permit may not be necessary. To avoid unnecessary delays, we recommend contacting VALROC Development Ltd. for an expert assessment. We handle the entire process, including determining permit requirements and working with local authorities to streamline approvals.
Langley has been a key service area for VALROC Development Ltd., where we have completed a diverse range of projects for residential, commercial, and strata clients. Our completed work includes:
Langley has been a core service area for VALROC Development Ltd., where we have completed a diverse range of construction projects, including:
We specialize in building custom homes, working closely with clients to develop designs that meet their vision. Our experience includes full-property developments, energy-efficient homes, and luxury estates.
Our team has installed durable, high-quality concrete driveways, sidewalks, and patios across Langley. We focus on proper site preparation and use premium materials to ensure longevity.
We provide full excavation services for new construction projects, including foundation digs, trenching, and grading. Proper excavation is critical to the success of any structure.
Langley businesses and property managers rely on us for durable asphalt installations, including parking lots, private roads, and commercial driveways.
Our team has built engineered retaining walls designed to protect properties from erosion and manage land stability effectively.
Ensuring proper drainage is essential for protecting a home’s foundation. We offer drain tile repairs and comprehensive water management solutions.
We regularly partner with strata councils and commercial property managers to perform renovations, maintenance, and large-scale infrastructure improvements.
If you’re considering a construction project in Langley, contact us to learn how we can assist from start to finish.
Langley has been a key service area for VALROC Development Ltd., where we have completed a diverse range of projects for residential, commercial, and strata clients. Our completed work includes:
Langley has been a core service area for VALROC Development Ltd., where we have completed a diverse range of construction projects, including:
We specialize in building custom homes, working closely with clients to develop designs that meet their vision. Our experience includes full-property developments, energy-efficient homes, and luxury estates.
Our team has installed durable, high-quality concrete driveways, sidewalks, and patios across Langley. We focus on proper site preparation and use premium materials to ensure longevity.
We provide full excavation services for new construction projects, including foundation digs, trenching, and grading. Proper excavation is critical to the success of any structure.
Langley businesses and property managers rely on us for durable asphalt installations, including parking lots, private roads, and commercial driveways.
Our team has built engineered retaining walls designed to protect properties from erosion and manage land stability effectively.
Ensuring proper drainage is essential for protecting a home’s foundation. We offer drain tile repairs and comprehensive water management solutions.
We regularly partner with strata councils and commercial property managers to perform renovations, maintenance, and large-scale infrastructure improvements.
If you’re considering a construction project in Langley, contact us to learn how we can assist from start to finish.
Selecting a contractor requires careful research to ensure you’re hiring a reputable and experienced company. Here’s what to look for:
Many homeowners in Langley have praised VALROC Development Ltd. for our transparent estimates, detailed contracts, and quality workmanship. Contact us for a consultation today.
Selecting a contractor requires careful research to ensure you’re hiring a reputable and experienced company. Here’s what to look for:
Many homeowners in Langley have praised VALROC Development Ltd. for our transparent estimates, detailed contracts, and quality workmanship. Contact us for a consultation today.
Before beginning any construction project, it’s important to plan accordingly:
VALROC provides full-service construction solutions, helping homeowners and businesses navigate these steps smoothly. Call us to discuss your project.
Before beginning any construction project, it’s important to plan accordingly:
VALROC provides full-service construction solutions, helping homeowners and businesses navigate these steps smoothly. Call us to discuss your project.
Zoning regulations determine what can be built on a property, including setbacks, lot coverage, and permitted uses. For example:
Before starting any project, it’s crucial to understand these regulations. Our team at VALROC Development Ltd. is well-versed in Langley’s zoning laws and can guide you through the process to avoid compliance issues.
Zoning regulations determine what can be built on a property, including setbacks, lot coverage, and permitted uses. For example:
Before starting any project, it’s crucial to understand these regulations. Our team at VALROC Development Ltd. is well-versed in Langley’s zoning laws and can guide you through the process to avoid compliance issues.
If you notice something that doesn’t seem right during construction, follow these steps:
VALROC prioritizes open communication with clients, ensuring that all concerns are addressed quickly and professionally.
If you notice something that doesn’t seem right during construction, follow these steps:
VALROC prioritizes open communication with clients, ensuring that all concerns are addressed quickly and professionally.
Depending on your project, you may need to work with Langley’s Engineering Department, Building Department, or Zoning Officials. Here’s what you need to know:
Instead of navigating these processes alone, let VALROC handle the approvals, permits, and inspections for you. We work directly with city officials to keep your project compliant and on schedule.
Contact VALROC Development Ltd. Today! Ready to start your construction project in Langley, BC? Our team offers expert guidance, quality craftsmanship, and reliable service. Call us today to schedule your free on-site estimate.
Depending on your project, you may need to work with Langley’s Engineering Department, Building Department, or Zoning Officials. Here’s what you need to know:
Instead of navigating these processes alone, let VALROC handle the approvals, permits, and inspections for you. We work directly with city officials to keep your project compliant and on schedule.
Contact VALROC Development Ltd. Today! Ready to start your construction project in Langley, BC? Our team offers expert guidance, quality craftsmanship, and reliable service. Call us today to schedule your free on-site estimate.