WeWeb has two ways to show or hide elements: CSS display binding (element stays in DOM, hidden via display:none — faster to toggle) and Conditional Rendering (element removed from DOM when false — faster initial page load). Use Conditional Rendering for large sections users rarely see. Use display binding for elements that toggle frequently. Critical security note: visibility in WeWeb is UX only — hidden data is still in the browser. Backend RLS is your real security layer.
WeWeb Conditional Visibility: Two Methods, One Goal
Showing and hiding UI elements based on conditions is fundamental to every web application — loading states, auth-gated content, role-specific interfaces, mobile vs desktop layouts, and progressive disclosure all rely on conditional visibility. WeWeb provides two distinct mechanisms: CSS display binding (which hides the element visually while keeping it in the DOM) and Conditional Rendering (which removes the element from the DOM entirely). Choosing the right method for each situation affects both performance and user experience. This tutorial walks through both methods, all binding types (variables, formulas, user roles), responsive visibility, and the critical security constraint you must understand before hiding any sensitive content.
Prerequisites
- A WeWeb project with elements you want to show or hide conditionally
- At least one WeWeb variable created (Data panel → Variables → + New) to use as a visibility trigger
- Basic understanding of WeWeb's formula editor (the binding window accessible via the plug icon)
Step-by-step guide
Understand the two visibility methods and when to use each
Understand the two visibility methods and when to use each
Before adding any conditional visibility, decide which method fits your use case. Method 1 — CSS display binding: the element is always in the DOM (rendered in HTML), but its display CSS property is toggled between 'flex'/'block' and 'none'. The element renders and takes up JavaScript memory even when invisible. Use this for: elements that toggle frequently (e.g., a loading spinner that appears and disappears during data fetching), dropdowns and modals, or elements where you need to preserve their internal state (input values, scroll position) while they are hidden. Method 2 — Conditional Rendering: the element is completely removed from the DOM when the condition is false. The element does not render at all, saving memory and rendering time. Use this for: large sections users rarely see (e.g., an admin panel visible only to admins), content behind authentication, or content-heavy sections that would slow down initial page load if always rendered.
Expected result: You can identify which method is appropriate for each visibility use case in your project.
Create a Boolean variable to control visibility
Create a Boolean variable to control visibility
The simplest conditional visibility pattern uses a Boolean variable. In the WeWeb editor, open the Data panel (database/layer icon in the left navigation bar) → click Variables → click + New. In the variable creation dialog: name the variable descriptively (e.g., 'isMenuOpen', 'showFilters', 'isLoading'), set the type to Boolean, and set the default value to false. Click Save. This variable will control whether an element is visible. You can toggle it from workflow actions: add a workflow to a button → add the action 'Change variable value' → select your Boolean variable → set the value to the opposite of current (use the formula: !variables['isMenuOpen']). Now your button toggles the visibility state.
Expected result: A Boolean variable exists in your Data panel → Variables list with a default value of false, ready to be bound to element visibility.
Apply CSS display binding to toggle an element
Apply CSS display binding to toggle an element
CSS display binding is configured in the Styling panel. Select the element you want to show or hide → open the Styling panel → in the Layout section, find the Display property (it shows values like 'flex', 'block', 'grid'). Click the plug icon (🔌) next to the Display property to open the binding formula editor. Write a formula that returns the appropriate display value when visible, or 'none' when hidden. The most common pattern is an if() formula: if(variables['isMenuOpen'], 'flex', 'none'). When your Boolean variable is true, the element gets display:flex and shows. When false, it gets display:none and hides. The element remains in the DOM at all times — you can still access its internal input variables even when hidden.
1// Formula editor — bind to Display property in Styling panel → Layout2// Basic boolean toggle3if(variables['isMenuOpen'], 'flex', 'none')45// Show loading state during collection fetch6if(collections['userData']['isFetching'], 'flex', 'none')78// Show error message when collection fetch fails9if(variables['hasError'], 'flex', 'none')1011// Show element only when collection has data12if(collections['products']['length'] > 0, 'flex', 'none')1314// Show for specific user role (see security note in later step)15if(variables['currentUser']['role'] === 'admin', 'flex', 'none')Expected result: The element hides (display:none) when the condition is false and shows again when the condition is true, toggling smoothly.
Apply Conditional Rendering to remove elements from the DOM
Apply Conditional Rendering to remove elements from the DOM
Conditional Rendering is configured in the element Settings panel (not Styling panel). Select the element you want to conditionally render → in the right panel, click the Settings tab (gear icon at the top of the panel, separate from the Styling tab). Scroll down to find the Conditional Rendering section. Click the toggle or the bind icon next to it. The formula editor opens. Write a condition that returns true (element renders) or false (element removed from DOM). Examples: variables['isAuthenticated'] shows content only when logged in; variables['userRole'] === 'admin' shows admin sections. When the condition becomes false, the element and all its children are completely removed from the DOM. This cannot preserve input values — if a form inside a conditionally rendered container is hidden, its input values are lost.
1// Formula editor — bind to Conditional Rendering in element Settings tab2// Show section only to authenticated users3variables['isAuthenticated']45// Show admin panel only to admin role6variables['currentUser']['role'] === 'admin'78// Show empty state when collection has no data and is not loading9!collections['products']['isFetching'] && collections['products']['length'] === 01011// Show content only when data is fully loaded12collections['userData']['isFetched'] && !collections['userData']['isFetching']1314// Multi-step form: show step 2 only after step 1 is valid15variables['step1Completed'] === true1617// Show notification banner only when there is a message18variables['notificationMessage'] !== '' && variables['notificationMessage'] !== nullExpected result: The element is completely absent from the DOM when the condition is false, reducing the rendered element count and improving initial load performance.
Implement role-based visibility for multi-role interfaces
Implement role-based visibility for multi-role interfaces
Role-based visibility shows different UI elements to different user roles — admins see admin controls, managers see manager-specific dashboards, and regular users see the standard interface. First, ensure your authentication is set up and user roles are available in a variable or collection. With Supabase Auth: after login, the user's role is typically in the Supabase Auth plugin's user object. Navigate to Plugins → Authentication → your auth plugin → check what user metadata is available. Store the role in a WeWeb variable (e.g., 'currentUserRole') in an 'On app load' or 'On page load' workflow using a 'Change variable value' action. Then bind Conditional Rendering on your role-specific elements to conditions like variables['currentUserRole'] === 'admin'. Stack multiple conditions using && and || operators for complex role logic.
1// Formula for role-based conditional rendering2// Single role check3variables['currentUserRole'] === 'admin'45// Multiple roles allowed (OR logic)6variables['currentUserRole'] === 'admin' || variables['currentUserRole'] === 'manager'78// Exclude a specific role9variables['currentUserRole'] !== 'trial'1011// Array-based roles (user has multiple roles)12variables['userRoles'].includes('billing')1314// Nested condition: authenticated AND specific role15variables['isAuthenticated'] && variables['currentUserRole'] === 'admin'1617// Show 'upgrade' banner only to free users who are logged in18variables['isAuthenticated'] && variables['subscriptionTier'] === 'free'Expected result: Different user roles see different UI elements. Admin controls are conditionally rendered and absent from the DOM for non-admin users.
Configure breakpoint-specific visibility for responsive layouts
Configure breakpoint-specific visibility for responsive layouts
WeWeb's breakpoint system allows you to override CSS properties per breakpoint, including the Display property. To make an element visible only on desktop and hidden on mobile: select the element → in the editor top navigation bar, click the breakpoint selector and switch to Mobile (≤767px) → with Mobile breakpoint active, open the Styling panel → find the Display property → bind it or set it to 'none'. Now on mobile, the element is hidden. Switch back to Desktop breakpoint — the Desktop display value is still 'flex' or 'block'. This approach uses CSS media queries under the hood. For a hamburger menu that appears on mobile but not desktop: create the hamburger menu element → on Desktop breakpoint set Display to 'none' → on Mobile breakpoint set Display to 'flex'. This works alongside variable-based bindings — you can layer both.
Expected result: Elements have different visibility at different screen sizes, verified by resizing the browser in the editor's breakpoint preview mode.
Show loading and empty states using collection metadata
Show loading and empty states using collection metadata
Collections in WeWeb expose metadata variables that are perfect for conditional visibility: isFetching (boolean, true while data is loading), isFetched (boolean, true after first successful fetch), length (number, count of items), and total (number, total items from server). Use these to build proper loading and empty states. For a loading skeleton: create a skeleton container → bind Conditional Rendering to collections['yourCollection']['isFetching']. For an empty state message: create an empty state component → bind Conditional Rendering to: !collections['yourCollection']['isFetching'] && collections['yourCollection']['length'] === 0. For the actual content list: bind Conditional Rendering to collections['yourCollection']['length'] > 0. These three states cover all data loading scenarios cleanly.
1// Conditional Rendering formulas for collection state UI23// Show skeleton/loading state4collections['products']['isFetching']56// Show empty state (not loading AND no items)7!collections['products']['isFetching'] && collections['products']['length'] === 089// Show actual content (has items)10collections['products']['length'] > 01112// Show error state (after fetch completed with no data unexpectedly)13collections['products']['isFetched'] && !collections['products']['isFetching'] && collections['products']['length'] === 0 && variables['hasFetchError']1415// Show pagination only when there are more items than shown16collections['products']['total'] > collections['products']['length']Expected result: Loading skeleton shows during data fetch, empty state shows when no data exists, and content shows when data is available — all driven by collection metadata.
Understand the security limitation of conditional visibility
Understand the security limitation of conditional visibility
This is the most important step in this tutorial. Conditional visibility in WeWeb is a UX mechanism, not a security mechanism. When you hide an element using either display binding or conditional rendering, you are changing what the user sees in their browser — but the underlying data may still have been fetched from your backend and is present in the browser's memory or network responses. A technically savvy user can open browser DevTools, inspect network requests, or manipulate the JavaScript context to read data that is 'hidden'. This means: hidden admin interfaces with sensitive data are visible to any determined user. Hiding form fields does not prevent their values from being submitted. Conditional visibility for premium content does not prevent free users from accessing it. The real security layer is always your backend: Supabase RLS policies, Xano endpoint authorization, or REST API authentication. Make sure your backend only returns data the authenticated user is authorized to see — regardless of what the frontend shows or hides.
Expected result: You understand that frontend visibility is UX-only and have verified your backend has proper authorization to match the frontend access controls.
Complete working example
1// ============================================================2// WeWeb Conditional Visibility — Formula Reference3// Use these in the formula editor when binding:4// - Display property (Styling panel → Layout → Display)5// - Conditional Rendering (Settings tab → Conditional Rendering)6// ============================================================78// --- Authentication state ---9// Show only to logged-in users10variables['isAuthenticated']1112// Show only to logged-out users (login/signup prompts)13!variables['isAuthenticated']1415// --- Role-based visibility ---16// Single role17variables['currentUserRole'] === 'admin'1819// One of several roles20['admin', 'manager', 'editor'].includes(variables['currentUserRole'])2122// Exclude specific role23variables['subscriptionTier'] !== 'free'2425// --- Collection / data state ---26// Loading indicator27collections['items']['isFetching']2829// Content list30collections['items']['length'] > 03132// Empty state33!collections['items']['isFetching'] && collections['items']['length'] === 03435// Pagination controls36collections['items']['total'] > 203738// --- UI state ---39// Boolean toggle (display binding)40if(variables['isOpen'], 'flex', 'none')4142// Multi-step form navigation43variables['currentStep'] === 24445// Show error message46variables['errorMessage'] !== '' && variables['errorMessage'] !== null4748// Show success state49variables['formSubmitted'] === true5051// --- Combined conditions ---52// Authenticated admin with active subscription53variables['isAuthenticated'] && 54variables['currentUserRole'] === 'admin' && 55variables['subscriptionActive'] === true5657// Show 'upgrade' CTA: logged in, not on premium58variables['isAuthenticated'] && variables['plan'] === 'free'5960// Show content when collection loaded and no error61collections['data']['isFetched'] && 62!variables['fetchError'] && 63collections['data']['length'] > 0Common mistakes
Why it's a problem: Using Conditional Rendering on a form container and expecting input values to persist when the form is re-shown
How to avoid: Conditional Rendering removes the element from the DOM, which destroys its internal state including input values. For multi-step forms where you need to go back to a previous step, use CSS display binding instead — the inputs stay in the DOM and preserve their values.
Why it's a problem: Relying on conditional visibility to protect sensitive data (e.g., hiding admin panels from regular users)
How to avoid: Frontend visibility is UX only — determined users can see hidden data in browser DevTools. Always protect sensitive data at the backend level with Supabase RLS policies or API authentication, regardless of what the frontend shows or hides.
Why it's a problem: Setting the display binding formula to return 'true' or 'false' instead of a CSS display value
How to avoid: The Display property expects a valid CSS display value ('flex', 'block', 'grid', 'none') — not a boolean. Use an if() formula: if(myCondition, 'flex', 'none'). Returning 'true' will literally set display:true which is not valid CSS.
Why it's a problem: Using breakpoint display:none on Desktop expecting elements to also hide on Mobile and Tablet
How to avoid: WeWeb uses desktop-first cascade. Setting display:none on Desktop propagates to Tablet and Mobile breakpoints. But if Mobile has display:flex from a previous setting, Mobile overrides Desktop's none. Set visibility per-breakpoint explicitly if you need fine-grained control.
Best practices
- Use Conditional Rendering for large sections that are rarely needed (admin panels, premium content) — it improves initial page load by not rendering unused DOM
- Use CSS display binding for elements that toggle frequently (loading spinners, dropdown menus, error messages) — toggling CSS is faster than adding and removing DOM nodes
- Always pair frontend conditional visibility with backend authorization — never assume hidden means inaccessible
- Use collection metadata (isFetching, length, isFetched) for loading and empty state patterns rather than separate Boolean variables that require manual management
- Name visibility variables semantically — 'isMenuOpen' not 'menuBool', 'showFilters' not 'filterToggle'
- Test conditional visibility for all user roles in your application — log in as each role type to verify the correct elements are shown and hidden
- Document role-based visibility decisions in comments or a team wiki — conditional rendering rules can become complex in multi-role apps and are hard to understand without context
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a WeWeb app with multiple user roles (admin, editor, viewer). I want to show different navigation menu items based on the current user's role. What is the correct approach in WeWeb — should I use CSS display binding or Conditional Rendering for role-based menu items, and what formula do I write to check the user's role?
In my WeWeb project, I have a data table with collection data. I want to show a loading skeleton while data is fetching, an empty state message when there is no data, and the actual table when data is loaded. How do I use WeWeb's collection metadata variables (isFetching, isFetched, length) with Conditional Rendering to implement these three states correctly?
Frequently asked questions
Can I animate the show/hide transition when using Conditional Rendering?
CSS transitions do not work with Conditional Rendering because the element is instantly added or removed from the DOM — there is nothing to transition. For animated show/hide effects (fade in, slide down), use CSS display binding instead. Set display between 'flex' and 'none', and add a CSS transition on opacity or transform to create a smooth visual effect.
Can I access the value of an input that is inside a conditionally rendered container when it is hidden?
No. When a container's Conditional Rendering condition is false, the entire container and all child elements are removed from the DOM. Input values inside are destroyed. Use CSS display binding (which keeps elements in the DOM) if you need to preserve input values while elements are hidden, such as in a multi-step form where users can navigate back.
Is Conditional Rendering in WeWeb the same as v-if in Vue.js?
Yes, functionally equivalent. WeWeb's Conditional Rendering maps to Vue's v-if directive under the hood — the element is only added to the DOM when the condition is true, and removed when false. CSS display binding maps to v-show, which keeps the element in the DOM but toggles its CSS display property.
How do I show a 'no results' message when a search returns zero items from a collection?
Use Conditional Rendering on the 'no results' message element, bound to the formula: !collections['yourCollection']['isFetching'] && collections['yourCollection']['length'] === 0. This shows the message only when the collection has finished loading and returned zero items. Also add Conditional Rendering on the results container bound to the inverse: collections['yourCollection']['length'] > 0.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation