The window's size class, {horizontal, vertical}, each :compact or
:regular.
Every screen socket carries it as assigns.size_class. The framework sets it
before mount/3 and keeps it current; a screen never asks for it.
Size classes are the layout signal, not orientation or raw dimensions. An iPad in Split View is a phone-shaped window on a tablet; a foldable flips class when it opens. Typical values:
| Window | Size class |
|---|---|
| iPhone, portrait | {:compact, :regular} |
| Large iPhone (Plus, Pro Max, XR/11-class, 414pt wide or more), landscape | {:regular, :compact} |
| Smaller iPhones, landscape | {:compact, :compact} |
| iPad full screen, either orientation | {:regular, :regular} |
| iPad Slide Over, narrow Split View | {:compact, :regular} |
| Android phone, portrait | {:compact, :regular} |
| Android phone, landscape | {:regular, :compact} |
| Android tablet / unfolded foldable | {:regular, :regular} |
Where the value comes from
- iOS — the window's
traitCollection.horizontalSizeClassand.verticalSizeClass, exactly as UIKit reports them. - Android — Android has no OS size class, so it is derived from the
activity's
Configuration.screenWidthDp/screenHeightDpwith the Material window-size-class breakpoints: horizontal is:compactbelow 600dp wide, vertical is:compactbelow 480dp tall; Material's "medium" and "expanded" both map to:regular. These are the numbers Android's ownw600dp/h480dpresource qualifiers select on. Seedecisions/2026-10-01-size-class-in-socket-assigns.mdfor why this and not Compose'sWindowSizeClass.
Changes
When the window's class changes — rotation, an iPad Split View / Slide Over /
Stage Manager resize, an Android multi-window resize, a foldable opening —
every live screen gets the new value in assigns.size_class and then
handle_info({:mob_size_class_changed, new}, socket). By the time that
callback runs the assign already holds new; a screen that only reads
assigns.size_class in render/1 needs no clause at all, and one without a
matching clause is not crashed by it.
Before the platform can answer
On iOS the BEAM can start before a window exists (a prewarmed or background
launch). Screens mounted then hold placeholder/0; the root view reports the
real value as soon as it appears, which arrives as an ordinary change.
Mob.ScreenCase.mount_screen/4 uses the same placeholder unless told
otherwise.
Summary
Functions
The value a screen holds when the platform cannot answer yet, and the
default under Mob.ScreenCase: {:compact, :regular}, a portrait phone.
True for a well-formed size class.
Types
Functions
@spec placeholder() :: t()
The value a screen holds when the platform cannot answer yet, and the
default under Mob.ScreenCase: {:compact, :regular}, a portrait phone.
True for a well-formed size class.