Mob.SizeClass (mob v0.9.13)

Copy Markdown View Source

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:

WindowSize 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.horizontalSizeClass and .verticalSizeClass, exactly as UIKit reports them.
  • Android — Android has no OS size class, so it is derived from the activity's Configuration.screenWidthDp / screenHeightDp with the Material window-size-class breakpoints: horizontal is :compact below 600dp wide, vertical is :compact below 480dp tall; Material's "medium" and "expanded" both map to :regular. These are the numbers Android's own w600dp / h480dp resource qualifiers select on. See decisions/2026-10-01-size-class-in-socket-assigns.md for why this and not Compose's WindowSizeClass.

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

Types

One axis of a size class.

t()

{horizontal, vertical}.

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

class()

@type class() :: :compact | :regular

One axis of a size class.

t()

@type t() :: {class(), class()}

{horizontal, vertical}.

Functions

placeholder()

@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.

valid?(arg1)

@spec valid?(term()) :: boolean()

True for a well-formed size class.