---
title: "ShelfWidgetLayout, DroppyKit"
description: "What a widget mount is, and the box it draws in (DroppyKit 1.23.0)."
canonical: "https://getdroppy.app/docs/droppykit/api/shelf-widget-layout"
last-updated: "2026-09-09"
---

# ShelfWidgetLayout

What a widget mount is, and the box it draws in (DroppyKit 1.23.0).

`struct ShelfWidgetLayout`

The host builds one for every mount and hands it to [`makeWidgetContent(_:layout:)`](https://getdroppy.app/docs/droppykit/api/shelf-widget-composition-providing#make-widget-content-layout), and the same value is in the environment (`dropletWidgetLayout`) for every building block inside the widget. Branch on `mode`, never on a width: `density` is already the host's answer to "how much room".

Available from DroppyKit 1.23.0.

## Cases

### ShelfWidgetLayout.Mode.single

`case single`

Alone on the shelf: the full single composition.

### ShelfWidgetLayout.Mode.singleWrapped(_:)

`case singleWrapped(ShelfWidgetNotchWrap)`

Alone on the shelf with the header row wrapped beside the camera (a notched Mac or the camera island): the single composition, with [`ShelfWidgetHeader`](https://getdroppy.app/docs/droppykit/api/shelf-widget-header) drawn into the bands.

### ShelfWidgetLayout.Mode.split(_:)

`case split(ShelfWidgetPlacement)`

Sharing a row with one to three other widgets: the split composition, in this slot.

### ShelfWidgetLayout.Density.regular

`case regular`

Alone on the shelf.

### ShelfWidgetLayout.Density.compact

`case compact`

In a row of two to four widgets.

### ShelfWidgetLayout.Density.tight

`case tight`

In a row so full the card is narrower than [`tightCardWidth`](https://getdroppy.app/docs/droppykit/api/droppy-widget-metrics#tight-card-width): drop the least essential control, as Pomodoro does.

## Initializers

### init(mode:density:contentSize:surface:isInteractive:isPreview:isVisible:usesAdaptiveForegrounds:foreground:)

`init(mode: Mode, density: Density, contentSize: CGSize, surface: DropletSurfaceKind, isInteractive: Bool, isPreview: Bool, isVisible: Bool, usesAdaptiveForegrounds: Bool, foreground: Color)`

Creates a layout. Constructed by hosts, read by droplets.

## Properties

### contentSize

`let contentSize: CGSize`

The settled box inside the host's insets, in points at the Regular shelf size: exactly what the widget's content is laid out in. Never a frame from the middle of a spring. Its height is zero while the host has not measured the card yet (the first frame of a mount, a preview); lay out to the box, not to this number.

### density

`let density: Density`

How much room the mount has.

### foreground

`let foreground: Color`

The primary ink: the user's Widget Text colour when one applies, the label colour under adaptive foregrounds, white on the notch.

### isInteractive

`let isInteractive: Bool`

`false` while the shelf springs open or closed and in a preview: the host takes no clicks then and blocks animations, so do not start one.

### isPreview

`let isPreview: Bool`

The mount is a non-interactive preview (Settings, the Custom Shelf editor, the harness's screenshots). Skip side effects.

### isSingle

`var isSingle: Bool { get }`

The widget is alone on the shelf, wrapped or not.

### isSplit

`var isSplit: Bool { get }`

The widget shares its row.

### isVisible

`let isVisible: Bool`

The mount is on a shelf the user can see. Pause timers, polling and animation while it is `false`.

### metrics

`let metrics: DroppyWidgetMetrics`

The metrics for this mount: spacing, control sizes, the type scale.

### mode

`let mode: Mode`

Where the widget is.

### notchWrap

`var notchWrap: ShelfWidgetNotchWrap? { get }`

The bands beside the camera while the header row is wrapped.

### placement

`var placement: ShelfWidgetPlacement { get }`

The widget's slot in its row; `.solo` alone.

### secondaryForeground

`var secondaryForeground: Color { get }`

The secondary ink (0.82 of `foreground`).

### surface

`let surface: DropletSurfaceKind`

The shelf's shape.

### tertiaryForeground

`var tertiaryForeground: Color { get }`

The tertiary ink (0.60 of `foreground`).

### usesAdaptiveForegrounds

`let usesAdaptiveForegrounds: Bool`

The host draws the shelf over a transparent notch and asks for adaptive foregrounds.

## Type methods

### density(isSplit:cardWidth:)

`static func density(isSplit: Bool, cardWidth: CGFloat?) -> Density`

The host's density rule: a card in a row narrower than [`tightCardWidth`](https://getdroppy.app/docs/droppykit/api/droppy-widget-metrics#tight-card-width) is tight, any other card in a row compact, a card alone regular.

### standardForeground(usesAdaptiveForegrounds:)

`static func standardForeground(usesAdaptiveForegrounds: Bool) -> Color`

The ink a mount uses before any Widget Text colour applies.
