Skip to main content
Version: Next

Breakpoint Layout New in 1.0.4

Breakpoint is the layout mode for a screen that should not merely reflow on a phone — it should be a different screen.

Flex adapts one layout: components wrap, resize and re-order, but it is the same set of widgets in the same relationships. Breakpoint replaces one subtree with another. At desktop width the operator sees the trend, the alarm table and the full control strip; at phone width they see three numbers and an acknowledge button. Not the same screen, smaller — a screen you drew for the phone.

That is also its cost: each tier you author is a screen you maintain. Reach for it when the wide and narrow versions genuinely differ, and for everything else use flex.

Tiers

A breakpoint container has a ladder of tiers, ordered smallest first. By default it is the project's own ladder — the same mobile / tablet / desktop vocabulary the shell, the grid layouts and the device toolbar already use:

TierApplies at
mobilebelow 600 px
tablet600 – 995 px
desktop996 px and above

Those two switch widths come from the project (Project Properties → Breakpoints), so changing them moves the shell, every responsive grid and every breakpoint view together. A container does not keep its own copy of the ladder, which is why the two can never drift apart.

Each tier has exactly one panel. A panel has no geometry of its own — it fills the container — and the container renders exactly one of them at a time.

The measurement is the container's, not the window's

A tier is chosen from the container's own measured box, never window.innerWidth. That is what makes breakpoint containers nest: one inside a narrow side panel switches to its narrow tier while the page around it is still at desktop.

Owning and mirroring

A panel either owns its subtree or mirrors another tier's.

A mirroring tier stores nothing of its own; it renders the panel it points at. Crossing into it is not a re-render at all — the same subtree stays mounted — so mirroring is free at runtime as well as in authoring effort.

A new three-tier container is seeded like this:

desktop owns its subtree ← what you see first, and draw on
tablet mirrors desktop
mobile owns its subtree ← the purpose-built narrow screen

Two authored screens, not three. That is the shape you almost always want: the phone is genuinely different, and the tablet is a slightly cramped desktop. A two-tier ladder seeds two owning panels and no mirror.

To give a mirroring tier its own layout, click the → mirrors Desktop row in the layer tree — it is a button, and it hands that panel its own empty subtree. Or set mirrors to None (own layout) in the Position panel.

Its tooltip states the thing worth knowing before you click: editing here edits Desktop, and giving this tier its own layout is a separate screen to maintain.

A mirror follows exactly one hop: a legal target is a panel that does not itself mirror. The dropdown is built from the live siblings, so it can only ever offer a legal target — which is why a mirror cycle is not something you can express, rather than something that is checked for afterwards.

"Tablet is broken" is usually a mirror doing its job

Resize the canvas to tablet width and you will often see the desktop screen, because the seeded tablet tier mirrors it. Everything about that is correct, and it reads as a fault.

The layer tree is where the ladder is legible — each tier with the width band it serves, and which one mirrors which:

Mobile < 600px
Tablet 600–995px → mirrors Desktop
Desktop ≥ 996px

That is deliberately the only place a tier is named. An indicator on the canvas would report the active tier while the Position panel reports the selected panel's tier, and at tablet width those legitimately disagree — the panel actually selected is the Desktop one. Two labels contradicting each other is worse than the gap one would close.

To see a different tier, resize: the device toolbar, or the canvas itself.

Authoring

Drilling into a breakpoint container and dropping a widget puts it in the panel that owns the visible tier. Resolved through the mirror: dropping while Tablet is on screen lands the widget in Desktop, which is where it will actually be seen. The same applies to paste.

Inside a panel, widgets are positioned by coordinates — a panel is a canvas, whatever the enclosing view's mode is.

A panel itself cannot be deleted or duplicated. There is one per tier and the container renders by looking one up, so a missing tier would render nothing and a duplicate would make "which panel serves this width" unanswerable. Remove a tier by editing the container's tiers instead, which tells you what that would destroy.

Settings

SettingDefaultWhat it does
tiersthe project'sThe ladder, smallest first. Set it only for a container that needs its own — ['small','large'] for a simple two-way swap
followProjectonSwitch at the project's breakpoints. Turn it off only to give this container its own thresholds
thresholdsCustom switch widths in px, ascending, one fewer than the number of tiers. Ignored while followProject is on
determinantwidthWhich dimension picks the tier. See the warning below before choosing height
hysteresis0Dead-band in px around every switch width
transitionnonenone, or fade
mountPolicylazylazy, keepAlive or eager — see below
overflowautoStandard overflow handling
padding0Inner padding, px

Leaving tiers, followProject and thresholds unset is the normal case, and nothing is written to the view until you actually diverge from the project.

Hysteresis

Raise it (8–24 px) if the layout flickers when the window rests near a switch width.

That flicker is real and has a specific cause: if two tiers differ in whether they scroll, the scrollbar changes the width that chose them — so the container switches, the scrollbar appears, the width drops back, and it switches again, every frame. A dead-band around each threshold ends it.

Determinant

width is almost always right. height is for a container inside a fixed-height region.

Height carries a hazard width does not

A panel's content determines the container's height, and with determinant: height that height selects the panel. Content can therefore change the tier that chose it.

Because of that, a minimum 24 px dead-band is applied whatever you set — you cannot take it back to zero. A zero dead-band there is not a preference, it is a live oscillation risk you have no way to see from the property grid.

Transition

none by default, and that is the right choice for an HMI: an operator reading a value should never wait on an animation. fade is opacity-only (140 ms, no movement, so it cannot shift a number mid-read) and is for a dashboard where the change is cosmetic. It is disabled automatically under the operator's reduced-motion setting.

Mount policy

PolicyBehaviourUse it for
lazy (default)Only the active tier is mounted. The others hold no subscriptions and run no scriptsAlmost everything
keepAliveMount on first activation, then hideA half-filled form, or a chart the operator has zoomed — state a swap would otherwise lose
eagerMount every tier up frontRarely
eager multiplies this view's tag subscriptions by the number of tiers

Three tiers of a subscription-heavy screen is three times the realtime traffic, permanently, for two screens nobody is looking at.

Converting a view into or out of breakpoint mode

Changing the layout mode of a breakpoint view rewrites what its root is, so QUBIQ restructures the view rather than just flipping a flag.

Into breakpoint — safe, and nothing is deleted. The root becomes a breakpoint container, the ladder is seeded, and every widget that was at the root moves into the largest owning tier. The view looks unchanged where you are standing, and tablet mirrors it.

Out of breakpoint — only one tier's widgets can survive, because the new root holds them directly and merging three screens would overlap them into nonsense. So the conversion is refused while another authored tier holds work, and it names the tiers and the widgets at risk. Confirm and it proceeds, keeping the largest owning tier.

A mirroring tier never triggers that refusal: it owns nothing, so warning about it would be noise you would learn to click through — which is how a guard stops working.

When not to use it

  • The layout only needs to reflow. Use flex. One layout that adapts is one layout to maintain.
  • Only a few widgets differ. Bind their visible property to session.device.type instead of authoring a second screen.
  • It is a dashboard of tiles. A responsive grid already reflows per breakpoint without a second subtree.
  • You would author three near-identical tiers. That is three screens to keep in step. Author two and mirror the middle.

Troubleshooting

SymptomCause
Tablet shows the desktop screenThe tablet tier mirrors desktop — the seeded default. The layer tree says so; click that row to give the tier its own layout
A widget vanished after dropping itIt landed in the tier that owns the visible one. Check the owning tier's panel
The layout flickers near a switch widthRaise hysteresis to 8–24 px
The tier changes when data arrivesdeterminant is height, and content is changing the height. Use width, or raise the dead-band
A tier renders emptyIts panel owns an empty subtree — either it never had content, or a broken mirror was cleared on load
Switching tiers is slowmountPolicy is eager or keepAlive on a heavy screen
A damaged view is repaired on load, not rejected

A view can arrive older, imported, hand-edited, or half-written by a crash mid-save. On load a missing tier is synthesised mirroring the nearest larger owning tier, a duplicate has its children salvaged into the panel that is kept, a broken mirror is cleared so the panel owns an empty subtree, and an orphaned tier is preserved and reported, never deleted. Authored work is not thrown away to make a document tidy.

Next

Property bindings