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();Surrey construction services
Trusted construction services for Surrey homeowners, strata councils, and businesses, delivered with proven experience, technical depth, and a focus on long-term performance.
Customer confidence
Surrey’s scale and variety require construction planning that responds to the specific neighbourhood, property use, soil, access, municipal process, and project scope.
(68 verified reviews)
Trusted by homeowners, strata communities, and businesses.
Impeccable safety record
Surrey includes established neighbourhoods, new development, strata communities, commercial sites, and industrial properties with very different operating conditions. We assess the actual location rather than treating the city as one uniform service area.
Customers gain a practical plan connecting municipal questions, access, equipment, materials, drainage, staging, and the services required for the agreed result.
Local construction planning
Construction planning in Surrey 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 site access, occupied areas, traffic, neighbours, deliveries, utility information, and room for equipment or materials affect the plan.
Review site access, occupied areas, traffic, neighbours, deliveries, utility information, and room for equipment or materials in relation to the result you want and the equipment or material movement the work may require.
Identify likely City residential permit, demolition, and land-development 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 Surrey property is actually used.
A practical route forward
The exact sequence depends on the work and property. Early review of City of Surrey requirements, access, disposal, equipment, and customer priorities helps turn an idea into a coordinated plan.
Identify likely permits, utility locates, disposal needs, technical details, and property-specific approvals before finalizing the scope.
Plan crews, machinery, materials, deliveries, hauling, protection, and staging around the neighbourhood and property use.
Complete the agreed sequence, review important site and finished details, and provide a clear customer handoff.
Review the intended result, property use, access, soil, drainage, occupants, neighbouring properties, 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.
With a strong portfolio of completed work, our experience ensures high-quality craftsmanship and efficient project execution.
We respect your time and space, ensuring efficient construction with minimal disruptions to your home or business.
Our contracts eliminate guesswork with clearly defined terms, pricing, timelines, and warranties, ensuring total transparency and peace of mind.
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 provides a base for selecting and staging equipment for Surrey 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.

I’ve been on council for our 26 years, we have been dealing with VALROC for over 6 years, our property manager brought “their” name up to us as a council and we have used VALROC to do a number of jobs here. The staff at the office are very very good to us and the staff on-site have been marvellous, they are very responsive to request, very responsive in showing us what’s been done and telling us how to enhance the work that has been done.



We had a sinkhole open up in our asphalt roadways, we have had two area’s that we have had to pave because of puddles forming and becoming dangerous in ice, we have had two roadways dugout and replaced 260 tons of asphalt put into here. Over the last couple of days, we have had a large amount again of asphalt brought in to address a health and safety issue and our mailbox area now concreted in because the previous bricks were up heaving and creating tripping hazards.
★★★★★
I've been on council for our 26 years, we have been dealing with VALROC for over 6 years, our property manager brought "their" name up to us as a council and we have used VALROC to do a number of jobs here. The staff at the office are very very good to us and the…
High-value planning information
Verified municipal, utility, recycling, and disposal contacts for construction decisions in Surrey. Use each section for a focused task, then confirm current requirements with the authority before acting.

Check Surrey residential permit requirements, Review permit information for residential construction and renovation.
Contact: 604-591-4366
Before you proceed: Requirements depend on the property and project scope. Confirm the correct permit type before preparing drawings.
Review Surrey demolition requirements, Check municipal requirements before demolishing a structure.
Contact: 604-591-4366
Before you proceed: Utility, hazardous-material, tree, and waste requirements may apply. Complete prerequisite checks before setting a demolition date.
Review Surrey land development requirements, Check planning and development steps that may affect project feasibility.
Contact: 604-591-4448
Before you proceed: Property-specific planning requirements may apply. Resolve planning questions before committing to a final sequence.
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 Central Surrey, Confirm whether the regional facility accepts the project material.
Contact: 604-432-6200
Before you proceed: Check accepted materials, fees, hours, and load restrictions. Separate materials before hauling when practical.
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.
Most construction projects in Surrey require a building permit to ensure compliance with local zoning bylaws and safety regulations. The Planning and Development Department at Surrey City Hall oversees permit applications, including:
• New builds and home additions
• Major renovations that alter structure or occupancy
• Retaining walls and excavation projects
• Demolition permits for structural removals
Some minor repairs and interior updates may not require a permit. However, zoning bylaws and engineering considerations still apply. If your project affects trees on city or private property, additional approvals may be required through the Tree Bylaw Office.
Navigating Surrey’s permit system can be complex, with multiple departments involved. VALROC Development Ltd. can assess your project, determine if a permit is required, and handle the application process for you.
For official information, contact Surrey Planning and Development at 604-591-4086 or planningdevelopment@surrey.ca.
Most construction projects in Surrey require a building permit to ensure compliance with local zoning bylaws and safety regulations. The Planning and Development Department at Surrey City Hall oversees permit applications, including:
• New builds and home additions
• Major renovations that alter structure or occupancy
• Retaining walls and excavation projects
• Demolition permits for structural removals
Some minor repairs and interior updates may not require a permit. However, zoning bylaws and engineering considerations still apply. If your project affects trees on city or private property, additional approvals may be required through the Tree Bylaw Office.
Navigating Surrey’s permit system can be complex, with multiple departments involved. VALROC Development Ltd. can assess your project, determine if a permit is required, and handle the application process for you.
For official information, contact Surrey Planning and Development at 604-591-4086 or planningdevelopment@surrey.ca.
Surrey’s Planning and Development Department provides online and in-person application options for building permits. To apply, you typically need:
• A completed application form
• Construction plans and engineering documents
• A site survey for zoning compliance
• Permit fees based on project size and scope
Applications can be submitted online through the Land, Planning & Development Portal or in person at City Hall, 13450 – 104 Avenue, Surrey, BC.
Since zoning, tree bylaws, and engineering requirements vary across Surrey’s neighborhoods, it’s best to consult with VALROC Development Ltd. to ensure your application is complete and accurate.
For permit inquiries, contact Surrey’s Building Approvals at 604-591-4086.
Surrey’s Planning and Development Department provides online and in-person application options for building permits. To apply, you typically need:
• A completed application form
• Construction plans and engineering documents
• A site survey for zoning compliance
• Permit fees based on project size and scope
Applications can be submitted online through the Land, Planning & Development Portal or in person at City Hall, 13450 – 104 Avenue, Surrey, BC.
Since zoning, tree bylaws, and engineering requirements vary across Surrey’s neighborhoods, it’s best to consult with VALROC Development Ltd. to ensure your application is complete and accurate.
For permit inquiries, contact Surrey’s Building Approvals at 604-591-4086.
The Board of Variance (BOV) in Surrey reviews applications for bylaw variances when compliance with zoning laws would cause undue hardship. This board may grant exceptions for:
• Building setback adjustments
• Minor zoning modifications that don’t require full rezoning
• Height restrictions and lot coverage adjustments
The Board does not approve major land use changes those require a rezoning process. If your project doesn’t meet zoning regulations, VALROC Development Ltd. can evaluate whether a Board of Variance application is necessary and guide you through the process.
For inquiries, contact BOVInquiry@surrey.ca.
The Board of Variance (BOV) in Surrey reviews applications for bylaw variances when compliance with zoning laws would cause undue hardship. This board may grant exceptions for:
• Building setback adjustments
• Minor zoning modifications that don’t require full rezoning
• Height restrictions and lot coverage adjustments
The Board does not approve major land use changes those require a rezoning process. If your project doesn’t meet zoning regulations, VALROC Development Ltd. can evaluate whether a Board of Variance application is necessary and guide you through the process.
For inquiries, contact BOVInquiry@surrey.ca.
Surrey’s expanding residential, commercial, and infrastructure developments have provided opportunities for a wide range of construction projects, including:
Custom Homes & Large-Scale Renovations
We have built luxury custom homes, major home additions, and full-scale renovations in Surrey, catering to homeowners looking for modern and energy-efficient designs.
Concrete Driveways, Sidewalks & Structural Pads
Our team has completed reinforced driveways, sidewalks, and foundation pads that meet Surrey’s engineering and zoning requirements.
Commercial & Industrial Developments
Businesses in Surrey have relied on our expertise for storefront construction, warehouse expansions, and industrial concrete projects.
Asphalt Paving for Parking Lots & Roadways
From residential driveways to large commercial parking lots, our asphalt paving services provide durable, high-quality results.
Excavation & Site Preparation
We specialize in grading, excavation, trenching, and land clearing for developments across Surrey.
Drainage & Retaining Wall Solutions
Given Surrey’s high rainfall levels and diverse terrain, proper drainage and erosion control are essential. We install engineered retaining walls, drainage systems, and stormwater solutions.
If you’re planning a construction project in Surrey, VALROC Development Ltd. can provide expert guidance and professional execution.
Surrey’s expanding residential, commercial, and infrastructure developments have provided opportunities for a wide range of construction projects, including:
Custom Homes & Large-Scale Renovations
We have built luxury custom homes, major home additions, and full-scale renovations in Surrey, catering to homeowners looking for modern and energy-efficient designs.
Concrete Driveways, Sidewalks & Structural Pads
Our team has completed reinforced driveways, sidewalks, and foundation pads that meet Surrey’s engineering and zoning requirements.
Commercial & Industrial Developments
Businesses in Surrey have relied on our expertise for storefront construction, warehouse expansions, and industrial concrete projects.
Asphalt Paving for Parking Lots & Roadways
From residential driveways to large commercial parking lots, our asphalt paving services provide durable, high-quality results.
Excavation & Site Preparation
We specialize in grading, excavation, trenching, and land clearing for developments across Surrey.
Drainage & Retaining Wall Solutions
Given Surrey’s high rainfall levels and diverse terrain, proper drainage and erosion control are essential. We install engineered retaining walls, drainage systems, and stormwater solutions.
If you’re planning a construction project in Surrey, VALROC Development Ltd. can provide expert guidance and professional execution.
Surrey’s zoning bylaws regulate:
• Building height and lot coverage limits
• Property setbacks from roads and adjacent properties
• Land use restrictions for residential, commercial, and industrial properties
If your project doesn’t align with Surrey’s zoning requirements, you may need a rezoning application or a variance request. Some zoning concerns include:
• Secondary suites and additional dwellings
• Heritage property regulations in areas like Cloverdale
• Environmental conservation zones near water bodies
VALROC Development Ltd. can assess zoning requirements before construction begins, preventing delays and ensuring compliance.
For zoning inquiries, contact Surrey Planning & Development at 604-591-4086.
Surrey’s zoning bylaws regulate:
• Building height and lot coverage limits
• Property setbacks from roads and adjacent properties
• Land use restrictions for residential, commercial, and industrial properties
If your project doesn’t align with Surrey’s zoning requirements, you may need a rezoning application or a variance request. Some zoning concerns include:
• Secondary suites and additional dwellings
• Heritage property regulations in areas like Cloverdale
• Environmental conservation zones near water bodies
VALROC Development Ltd. can assess zoning requirements before construction begins, preventing delays and ensuring compliance.
For zoning inquiries, contact Surrey Planning & Development at 604-591-4086.
Hiring an experienced and reputable contractor is key to a successful construction project. Here’s what to look for:
• Proven local experience – Contractors familiar with Surrey’s regulations will streamline permits and approvals.
• WorkSafe BC coverage & liability insurance – Protects homeowners from liability during construction.
• Customer testimonials & case studies – Reviews from past clients demonstrate reliability.
• Detailed contracts & pricing transparency – Avoid surprises with clear project timelines and cost breakdowns.
VALROC Development Ltd. is a trusted construction company in Surrey, specializing in excavation, paving, concrete, drainage, and full-scale renovations. Contact us for a consultation to ensure your project is handled professionally.
Hiring an experienced and reputable contractor is key to a successful construction project. Here’s what to look for:
• Proven local experience – Contractors familiar with Surrey’s regulations will streamline permits and approvals.
• WorkSafe BC coverage & liability insurance – Protects homeowners from liability during construction.
• Customer testimonials & case studies – Reviews from past clients demonstrate reliability.
• Detailed contracts & pricing transparency – Avoid surprises with clear project timelines and cost breakdowns.
VALROC Development Ltd. is a trusted construction company in Surrey, specializing in excavation, paving, concrete, drainage, and full-scale renovations. Contact us for a consultation to ensure your project is handled professionally.
Delays and cost overruns are common in construction due to permits, weather conditions, supply chain issues, and unexpected site challenges. To minimize risks:
• Secure all necessary permits before work begins
• Work with an experienced contractor familiar with Surrey’s building regulations
• Ensure clear project timelines and material availability
• Maintain consistent communication with your contractor
VALROC Development Ltd. follows proactive scheduling, detailed budgeting, and strict project management protocols to keep your project on track.
Conclusion
If you’re planning a home renovation, commercial construction, or site preparation project in Surrey, VALROC Development Ltd. offers expert guidance, top-quality craftsmanship, and professional execution.
📞 Contact us today for a free on-site estimate!
Delays and cost overruns are common in construction due to permits, weather conditions, supply chain issues, and unexpected site challenges. To minimize risks:
• Secure all necessary permits before work begins
• Work with an experienced contractor familiar with Surrey’s building regulations
• Ensure clear project timelines and material availability
• Maintain consistent communication with your contractor
VALROC Development Ltd. follows proactive scheduling, detailed budgeting, and strict project management protocols to keep your project on track.
Conclusion
If you’re planning a home renovation, commercial construction, or site preparation project in Surrey, VALROC Development Ltd. offers expert guidance, top-quality craftsmanship, and professional execution.
📞 Contact us today for a free on-site estimate!