SuperAPI AI Directory

capacitor-foldable

General & other

View repository

Updated 10-15 21:39

About this skill

Capacitor Foldable

Guidance for @erkamyaman/capacitor-foldable, which reports the fold to a Capacitor web view: where the crease is, the hinge angle, the posture, and which display the app is on.

This skill is new. Everything in it was checked against the plugin source and measured on the iPhone Duo simulator, but it has not been through much real use yet, so report anything that misleads you. It is maintained in the plugin's own repo, which is the copy that ships with the npm package.

Install

npm install @erkamyaman/capacitor-foldable
npx cap sync

Capacitor 8 uses the current major. Capacitor 7 apps install @erkamyaman/capacitor-foldable@7, which reports the fold on Android and size classes everywhere, but has no iPhone Duo support: a Capacitor 7 app built with Xcode 27 crashes at launch, because iOS 27 needs the scene lifecycle that Capacitor 8.5 and later adopted. The 7.x line also predates the --fold-* variables (8.1.0) and the Ionic tab stylesheets, so the CSS below needs Capacitor 8.

Start here: CSS before JavaScript

Install the polyfill once at startup, then lay out with CSS. Most foldable work needs no JavaScript at all.

import { Foldable, installFoldablePolyfill } from '@erkamyaman/capacitor-foldable';

await installFoldablePolyfill();

Whenever the device reports a fold, that sets --fold-left, --fold-top, --fold-width, --fold-height and --fold-margin-* on <html>, and adds fold-vertical or fold-horizontal. It also sets the vertical-bars-* classes the Ionic stylesheet needs, and fills in the standard Viewport Segments and Device Posture APIs, which Safari and Android's WebView do not provide.

Prefer the --fold-* variables over the polyfilled segment variables for layout: the segments only split when the fold actually separates the window, which on iPhone Duo means half open, while the fold variables are there when it is open flat too.

.fold-vertical .reader { position: fixed; inset: 0; }

.fold-vertical .reader .page {
  position: absolute;
  top: 0;
  bottom: 0;
  padding: 14px;
  box-sizing: border-box;
}

.fold-vertical .reader .page:first-child { left: 0; width: var(--fold-left); }
.fold-vertical .reader .page:last-child { left: calc(var(--fold-left) + var(--fold-width)); right: 0; }

On a phone with no fold there are no --fold-* variables and no fold-* class, so write the flat layout first and let these rules refine it. The install is also a no-op off native, so nothing appears in a desktop browser: iterate in the simulator or on a device.

Handle both orientations. On iPhone Duo the crease is vertical in landscape and horizontal in portrait, so a layout that only styles .fold-vertical flattens when the phone is turned.

Reach for the plugin's methods when CSS cannot answer the question: the hinge angle, the posture, which display you are on, or where the system put its bars.

When to consult these references

  • Laying out around the crease (variables, classes, worked layouts): css-layout.md
  • The API (methods, events, and what is platform specific): api.md
  • Ionic apps (ion-tabs on the side, the keyboard event a fold fires, Angular's CSS rule): ionic.md
  • iPhone Duo specifics (reserved regions, vertical bars, safe areas, what the hinge status gets wrong): iphone-duo.md
  • Android foldables (postures, rear display, dual screen): android.md
  • Testing (iPhone Duo simulator, foldable emulator, driving the hinge from the terminal): testing.md

Hard rules

  • ✅ Split on var(--fold-left), never on 50%. The variables give the band's leading edge, not its centre, and the coordinates are measured against the web view, so any inset moves them off the viewport midpoint. On iPhone Duo the fold is a 40 point band, so a halfway split also lands inside the part the system wants kept clear.
  • ✅ Treat --fold-width as the keep-clear band. The margins are inside it, so --fold-margin-* tells you how much of the band is margin rather than physical crease. Do not add them on top of it. They are iOS only and read 0px on Android, where a seamless fold also reports zero width, so keep your own minimum clearance: max(12px, var(--fold-width, 0px)), with the fallback because the variable does not exist at all on a phone with no fold.
  • ✅ Expect the fold when the device is fully open, not just half. The position is reported flat as well as folded, so a layout can line up with the crease before anyone bends anything. A closed device reports state: 'flat' and no hingeBounds, because the plugin drops the fold below 20 degrees.
  • ✅ Let the layout expand; do not design a screen per pose. Apple: "Don't reinvent your app when it resizes; allow the existing layout to expand based on the available space instead", and "Avoid extreme layout changes as people fold the device." Google's equivalent is to adapt to window size classes rather than device type, and to consider whether controls and text should avoid the hinge space.
  • ❌ Do not use setVerticalBarBehavior({ behavior: 'disabled' }) to avoid adapting. Apple's HIG asks you not to override bar placement. UIKit's own reference gives the exception: disable it only for interfaces better served by horizontal bars, "such as a fullscreen video player with toolbar controls or a non-scrolling layout like a calculator". It returns the bars to horizontal; it does not hand you the full display.
  • ❌ Do not poll getFoldState() on a timer when foldStateChange will tell you. The exception is the moment the app moves between displays, where iOS pauses the web view: see iphone-duo.md.
  • ❌ Do not confuse "this device folds" with "there is a fold on this screen". isDeviceFoldable() answers the first, though it can answer false on an Android foldable that advertises no tabletop posture and no hinge sensor. The presence of hingeBounds, or --fold-left in CSS, answers the second, and is what layout should key on. For the outer screen, neither is the gate: use getDisplayModes() and displayModeChange, since rear display and dual screen are Android only and read unsupported on iPhone Duo even though it folds. Every read method answers safely on any device; startRearDisplay() and startDualScreen() reject when the mode is unavailable.

Before reporting done

npm run build      # or the app's build
npx cap sync

Then run it open flat, half open and closed, and fold it shut and open again, which suspends and resumes the web view on iOS. On iPhone Duo the posture picks the display, so that covers both screens; on Android the outer display needs rear display mode. testing.md has the commands.