# Device.HasKeyboard — whether to show key hints

> `Device.HasKeyboard` is true when the page is used with keys worth hinting at: a mouse or a trackpad (a fine pointer that can hover), or once a physical key has been pressed on the page — so a tablet with a keyboard attached starts showing hints the first time it is used. False on a touch-only phone, and on the server.

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

## Summary        {#summary}

Show which keys move through a list where there are keys to press:

```osy title="key hints only where there are keys" test app=ui-device
[Route("/inbox")] [AllowAnonymous]
component InboxPage() {
  render {
    Stack(gap: 2) {
      Text("Your messages");
      if (Device.HasKeyboard) { Text("J and K move between messages"); }
    }
  }
}
```

## Signature      {#signature}

```osy syntax
Device.HasKeyboard   // bool — a mouse or a trackpad, or a physical key pressed on this page
```

## Description    {#description}

### How does it decide?   {#how}

No browser says whether a keyboard is attached, so the answer is worked out from two signs:

- **The pointer is a mouse or a trackpad.** A precise pointer that can hover almost always comes with keys — a
  laptop, a desk. This is known the moment the page renders.
- **A physical key was pressed on this page.** It settles the case the pointer cannot: a tablet with a keyboard
  case. From the first such key the answer is true for as long as the page is open. Typing on an on-screen keyboard
  does not count — a key pressed into a text field, or as part of an input method's composition, could have come from
  one. A key no on-screen keyboard has (Tab, Escape, the arrows, Home, End, Page Up/Down, F1–F12), a key pressed with
  Ctrl, Alt or Cmd held, or any key pressed outside a field does count.

### `Device.HasKeyboard` or `Viewport.AtLeast`?   {#which}

| You are deciding | Ask |
|---|---|
| whether to show key hints, a shortcut bar, a "press / to search" line | `Device.HasKeyboard` |
| whether the window is wide enough for a layout | `Viewport.AtLeast(Laptop)` ([Viewport.AtLeast and Layout.AtLeast — the window, or the room this component has](https://osysharp.com/reference/ui/viewport/)) |

A wide window is not a keyboard — a tablet in landscape is 1180px wide — and a narrow one may have one.

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

In `render`, where it follows the answer live (the hint appears the moment the first key is pressed), and in a client
action, where it is read once when the action runs. It is a `bool`, so it combines like any other:
`if (Device.HasKeyboard && Layout.AtLeast(Tablet)) { … }`.

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

`false` — the touch-first answer, as `Viewport.AtLeast` answers the narrow one. A server-rendered page paints no key
hints, and the browser adds them on its first render where they apply. A server function that reads it also gets
`false`: a server knows nothing about the hardware a page is used on.

### Can I name something `Device` myself?   {#shadowing}

Yes — a field, a parameter or a local called `Device` is yours, and `Device.HasKeyboard` then reads it, as a local
hides a type of the same name in C#.

## See also       {#see-also}

- [Viewport.AtLeast and Layout.AtLeast — the window, or the room this component has](https://osysharp.com/reference/ui/viewport/) — the window's width, and the room this component has
- [keys](https://osysharp.com/reference/ui/keys/) — key bindings and the hints that show them
