# Viewport.AtLeast and Layout.AtLeast — the window, or the room this component has

> Two questions with one shape. `Layout.AtLeast(Tablet)` asks whether THIS component's container is at least the breakpoint wide — the right question for "is there room for a table here". `Viewport.AtLeast(Tablet)` asks the same of the browser WINDOW — the right question for a decision about the device, such as showing key hints on a desk when the list they sit in is a narrow pane. Both follow their width live, and both answer false on the server.

<!-- id: ui-viewport · area: ui · stability: stable · html: https://osysharp.com/reference/ui/viewport/ -->

## Summary        {#summary}

A list pane 440px wide on a 1440px screen is narrow, and the screen is not. Ask the question you mean:

```osy title="the pane's room, and the device it is on" test app=ui-viewport
[Route("/inbox")] [AllowAnonymous]
component InboxPage() {
  render {
    Row(gap: 4) {
      Box(w: "440px") { InboxList(); }
      Box(grow: 1) { Text("Reading pane"); }
    }
  }
}

[Composable]
component InboxList() {
  render {
    Stack(gap: 2) {
      // The ROOM: this pane is never wide enough for columns, so it lays out as cards.
      if (Layout.AtLeast(Tablet)) { Text("Subject · From · Received"); }
      // The DEVICE: on a desk-sized window, say which keys move through the list.
      if (Viewport.AtLeast(Laptop)) { Text("J and K move between messages"); }
      Text("Your messages");
    }
  }
}
```

## Signature      {#signature}

```osy syntax
Viewport.AtLeast(<breakpoint>)   // is the browser window at least this wide?
Layout.AtLeast(<breakpoint>)     // is THIS component's container at least this wide?
```

## Description    {#description}

### Which one do I want?   {#which}

| You are deciding | Ask |
|---|---|
| whether a table fits, how many columns, cards or rows | `Layout.AtLeast` — the room the component was given |
| something about the DEVICE — key hints, a desk-only shortcut bar, a phone-only bottom bar | `Viewport.AtLeast` — the window |

A component placed in a narrow column should lay itself out narrow however wide the window is, which is why
`Layout.AtLeast` measures the container. But a narrow column on a wide window is still a desk with a keyboard in front
of it, and asking the container would hide a desk's key hints in exactly the pane where they help.

### Which names can I pass?   {#breakpoints}

A declared `Breakpoints` token, written bare — the kit declares `Phone` (480), `Tablet` (768), `Laptop` (1100),
`Desktop` (1440) and `Widescreen` (1680), and a theme may add its own ([theme tokens](https://osysharp.com/reference/ui/theming/)). The same names a `variants`
block's `Tablet { … }` override uses, so the two agree about where a layout changes.

### Where can I use them?   {#where}

In a `render` block. An action or function body may run on the server, where there is no window and nothing on
screen, so both are refused there with a message naming `render`; decide in `render` and pass the answer on.

### What does the server answer?   {#server}

`false` for both — mobile-first, the narrow arm. The browser corrects it on its first render, and from then on each
follows its own width: resizing the window re-renders a `Viewport.AtLeast` branch with nothing wired by the app.

### How do I test it?   {#test}

`Ui.Viewport(1440)` sets the window's width, before or after a visit: `Ui.Viewport(390)` mid-test makes the page
re-flow on the spot ([Ui — drive the app's UI from a test](https://osysharp.com/reference/testing/ui/)).

## See also       {#see-also}

- [theme tokens](https://osysharp.com/reference/ui/theming/) — declaring breakpoints, and styling at them
- [style props](https://osysharp.com/reference/ui/styling/) — style props, which take a breakpoint override instead of a branch
- [keys](https://osysharp.com/reference/ui/keys/) — key bindings and the hints that show them
- [Device.HasKeyboard — whether to show key hints](https://osysharp.com/reference/ui/device/) — `Device.HasKeyboard`: whether there are keys to hint at, which a window's width cannot tell
