Skip to content

CSS Class API ​

All Fold.page CSS classes use the foldpage prefix. They are added to standard HTML elements’ class attributes as usual.

Target Wrapper ↓ ​

  • .foldpage — Marks the region to render in 3D

Loading & FOUC Prevention ↓ ​

  • .foldpage-fouc — Hide content until Fold.page is ready, even before init() has run

Element Control ↓ ​

XR Visibility ↓ ​

Stylesheet Selectors ↓ ​


Target Wrapper ​

.foldpage ​

Identifies a root target element. This element and its children are scanned for supported elements and rendered in 3D. Content outside every .foldpage element is left untouched.

html
<div class="foldpage">
  <!-- Everything here is eligible for 3D rendering -->
  <h1>Title</h1>
  <p>Content</p>
</div>

The wrapper class is optional. Pass foldpage: true to Fold.init() to render the entire page body in 3D without adding any class to your HTML. See foldpage in the Configuration API.

Notes:

  • Content outside every .foldpage element is not touched by Fold.
  • Feature toggle classes (like .foldpage-grid) can be added to the same element.

See Getting Started for full setup details.


Scoped Target Wrapper(s) ​

You don't have to wrap your whole page. Add .foldpage to any single section, card, hero, or element to render only that region in 3D while the rest of the page stays as normal HTML.

html
<!-- Normal page content — untouched by Fold.page -->
<header>
  <nav>...</nav>
</header>

<!-- Only this hero section renders in 3D -->
<section class="foldpage">
  <h1>Spatial Headline</h1>
  <p>This paragraph renders as 3D text.</p>
  <img src="hero.jpg">
</section>

<!-- Normal page content — untouched by Fold.page -->
<footer>...</footer>

You can also use multiple independent wrappers — each one creates its own scoped 3D region:

html
<section class="foldpage">
  <h2>Feature One</h2>
  <p>Rendered in 3D.</p>
</section>

<!-- Normal HTML between the two 3D regions -->
<div class="plain-html-section">...</div>

<section class="foldpage">
  <h2>Feature Two</h2>
  <p>Also rendered in 3D — independent of the first wrapper.</p>
</section>

Each .foldpage element is processed independently. Fold.page builds a separate 3D element list for each wrapper, so the regions don't interfere with each other.

A scoped target doesn't need to wrap content — it can be the content. If the single element you're scoping already qualifies on its own (a <img>, a data-foldpage-model-src host, a .foldpage-bg/.foldpage-text element, etc.), just put .foldpage directly on it — no inner wrapper required:

html
<!-- Normal page content — untouched by Fold.page -->
<section class="card">
  <h2>Statement Plant</h2>
  <p>Normal DOM text — no Fold class here.</p>

  <!-- This single div is both the scope AND the content: a leaf .foldpage
       element carrying data-foldpage-model-src renders its own GLB model. -->
  <div class="foldpage" data-foldpage-model-src="/models/monstera.glb"
       style="width: 220px; height: 280px;"></div>
</section>

Loading & FOUC Prevention ​

.foldpage-fouc ​

Hides content until the 3D scene is ready, so visitors never see a flash of flat HTML before it appears. Without it, Fold hides nothing until Fold.init() runs.

Recommended setup: add this rule to your <head>, then add foldpage-fouc to the <body> or to any section you want hidden:

html
<head>
  <style>
    .foldpage-fouc {
      clip-path: inset(100%);
      pointer-events: none;
      animation: foldpage-fouc-fallback 0s 6s forwards;
    }
    @keyframes foldpage-fouc-fallback {
      to { clip-path: none; pointer-events: auto; }
    }
  </style>
</head>
<body class="foldpage-fouc">
  ...
</body>
  • Why the rule goes in your <head>: Fold injects the same rule when its script runs, but that can be after the first paint. A static rule hides the content from the very first frame.
  • The 6-second animation is a safety net: if Fold never loads (blocked script, no JavaScript), the content reappears after 6 seconds.
  • Fold removes the class when the 3D scene is ready. It also removes it shortly after page load if init() is never called, and right away if Fold can't render (unlicensed domain, error, failed download).

Element Control Classes ​

.foldpage-exclude ​

Excludes an element and its children from 3D rendering. The element remains visible in the DOM as normal HTML.

html
<h1 class="foldpage-exclude">
  This heading stays as flat HTML — not rendered in 3D.
</h1>

Use case: Navigation bars, form elements, interactive widgets, or anything you want to keep as standard 2D HTML while the rest of the page in the target wrapper goes 3D.

Combining with .foldpage-text: You can exclude a parent but include specific children:

html
<h1 class="foldpage-exclude">
  <!-- The h1 itself is excluded... -->
  <span class="foldpage-text">...but this span IS rendered in 3D</span>
</h1>

.foldpage-include ​

Forces visibility on elements that are hidden by default, then renders them in 3D.

html
<div class="foldpage-include" style="display: none;">
  <p>Hidden in 2D, but visible in the 3D scene.</p>
</div>

How it works: Fold normally skips hidden elements. Inside a .foldpage-include container, Fold sets display: block and visibility: visible before rendering, so the content appears in 3D while the flat page keeps it hidden.

Use case: Content you want visible only in the 3D/XR experience but hidden for standard 2D page viewing. This pattern prevents a flash of unstyled content (FOUC) — the content is hidden on page load and only appears once Fold.page renders it in 3D.


XR Visibility Classes ​

These classes control which HTML elements are visible based on whether the visitor's device supports WebXR (AR or VR).

.foldpage-xr ​

Shows the element only when the device supports WebXR. Hidden otherwise.

html
<p class="foldpage-xr" style="display: none;">
  Press Enter XR in the corner to view this page in your headset.
</p>

Use case: XR-specific instructions or content that only makes sense on spatial devices.

.foldpage-noxr ​

Shows the element only when the device does NOT support WebXR. Hidden otherwise.

html
<div class="foldpage-noxr" style="display: none;">
  <p>Visit this page on a WebXR-capable device for the immersive experience.</p>
</div>

Use case: Fallback messages encouraging users to try the page on a VR/AR device.

HDRI Background Visibility ​

When data-foldpage-hdr-src is placed on an element, .foldpage-xr and .foldpage-noxr also control which rendering context the HDRI sky is visible in:

  • .foldpage-xr on the HDR element → background visible in XR only
  • .foldpage-noxr on the HDR element → background visible on screen only
  • Neither class → background visible in both contexts
  • data-foldpage-hdr-background="false" → IBL only, no visible background in any context

IBL (environment lighting for GLB models) is always active regardless of these classes. See Environment (HDRI) for the full attribute reference.

Important: Both Classes Require style="display: none;" ​

Both .foldpage-xr and .foldpage-noxr elements should have style="display: none;" in your HTML. This prevents a flash of content before Fold's XR detection script runs. Fold.page will toggle the display property to block or none based on the detection result.

Fold checks for immersive-ar support first, then immersive-vr. If either is supported, .foldpage-xr elements are shown and .foldpage-noxr elements are hidden; otherwise the reverse.


Stylesheet Selectors ​

Fold adds these classes itself. Don't put them in your HTML — use them as selectors in your stylesheet.

.foldpage-el ​

Added to every element Fold renders, once the 3D scene is ready. Combine it with your own selector for CSS that should apply only in 3D and never to the flat page:

css
/* Push an image 100px toward the viewer in 3D only */
.section-image.foldpage-el { transform: translateZ(100px); }

/* Hide a decorative element in 3D only */
.decorative-divider.foldpage-el { display: none; }

/* Soften a caption in 3D only */
.caption-text.foldpage-el { opacity: 0.7; }

.foldpage-on ​

Added to a .foldpage wrapper once its 3D content is live. Use it for wrapper-level rules:

css
.foldpage.foldpage-on {
  cursor: none; /* e.g. hide the native cursor once your own 3D cursor takes over */
}

.foldpage-hover / .foldpage-hover-N ​

Your :hover rules work in 3D without changes. The real DOM element is hidden, so Fold copies each :hover rule to an equivalent .foldpage-hover rule and adds that class while the 3D element is hovered. For example, .card:hover { transform: translateY(-8px); } also applies to the hovered 3D card.

.foldpage-hover-1 … .foldpage-hover-5 are added to ancestors (up to 5 levels) while a descendant is hovered, so nested hover rules such as dropdown menus keep working.

.foldpage-active ​

Mirrors your :active rules while a pointer is held down on the element. Applies to the element itself only, not its ancestors.

.foldpage-focus ​

Mirrors your :focus rules while the element has keyboard focus. Applies to the element itself only. :focus-within and :focus-visible are not mirrored.

  • .foldpage-view-link-focused is on a data-foldpage-view-link element while the camera is framing its target, and is removed when that view is dismissed.
  • .foldpage-view-focused is on whichever data-foldpage-view element is fully in focus — whether reached by scrolling, a view link, or Fold.viewTo(). While the camera moves between views, no view has it.

Neither is related to keyboard focus.

css
/* Highlight a view-link nav item while its target is the active/open view */
[data-foldpage-view-link].foldpage-view-link-focused {
  outline: 2px solid #7cc7ff;
  outline-offset: 2px;
}

See Views & Navigation — Active View Styling for the full attribute reference these pair with.

Fold.page — 3D UI for the web.