---
title: "DropletHUDRequest, DroppyKit"
description: "A transient HUD to show in the notch."
canonical: "https://getdroppy.app/docs/droppykit/api/droplet-hudrequest"
last-updated: "2026-09-09"
---

# DropletHUDRequest

A transient HUD to show in the notch.

`struct DropletHUDRequest`

## Initializers

### init(id:duration:priority:accessibilityLabel:content:)

`init(id: String, duration: TimeInterval? = 2.0, priority: DropletHUDPriority = .normal, accessibilityLabel: String, @ViewBuilder content: @escaping @MainActor @Sendable () -> some View)`

### init(id:duration:priority:accessibilityLabel:isExpanded:expandedContentHeight:content:expanded:)

`init(id: String, duration: TimeInterval? = 2.0, priority: DropletHUDPriority = .normal, accessibilityLabel: String, isExpanded: Bool, expandedContentHeight: CGFloat? = nil, @ViewBuilder content: @escaping @MainActor @Sendable () -> some View, @ViewBuilder expanded: @escaping @MainActor @Sendable () -> some View)`

Creates a HUD that has both shapes.

A separate initializer rather than defaulted parameters on the one above: this module is resilient, so adding parameters to an existing initializer would change its symbol and break every droplet already compiled against it.

## Properties

### accessibilityLabel

`let accessibilityLabel: String`

Spoken description for VoiceOver.

### duration

`let duration: TimeInterval?`

How long the HUD stays up. `nil` keeps it until it is replaced or the droplet dismisses it.

### expandedContentHeight

`let expandedContentHeight: CGFloat?`

Height the card wants, in points, or `nil` for the host's standard expanded height.

The host adds the notch cutout itself, so this is the CONTENT height — the same number Droppy's own expanded HUDs state. It is clamped: a card taller than the surface can show is refused down to what fits.

### id

`let id: String`

Stable id. A second request with the same id replaces the first in place instead of queueing behind it.

### isExpanded

`let isExpanded: Bool`

Whether the card is showing rather than the strip.

Drive this from your own state and re-present with the SAME id: a second request with an id already on screen replaces the first in place, which is what makes the strip morph into the card on the host's own spring rather than dismissing and re-presenting as two HUDs.

A droplet HUD is mounted exactly like Droppy's own battery HUD, so its appearance, this morph and its close are Droppy's own motion. Neither `content` nor `expanded` takes an entrance transition of its own; swaps inside them use [`DroppyTransition`](https://getdroppy.app/docs/droppykit/api/droppy-transition).

### makeContent

`let makeContent: @MainActor @Sendable () -> AnyView`

The HUD's content. Built on demand and may be rebuilt on layout changes, so keep it a pure function of your model.

`@Sendable` is explicit rather than inferred. A host compiled with approachable concurrency (SE-0434) treats every global-actor-isolated function type as `@Sendable` already, while this module's interface is emitted without that feature. Leaving it implicit therefore made the two spellings of the SAME type disagree across the module boundary, and Droppy's own conformance to this protocol failed to compile with a "sendability of function types does not match" error that named no difference a reader could see. Written out, it means one thing everywhere.

### makeExpandedContent

`let makeExpandedContent: (@MainActor @Sendable () -> AnyView)?`

The card this HUD grows into, or `nil` when it only has the strip.

Droppy's own HUDs come in both shapes. A Wi-Fi chip is a strip and never anything else; a low battery and a pair of AirPods start as a strip and grow into a card with a title, a description and controls. The second shape is not a different HUD — same id, same slot, same surface — so it is the same request, and which one is on screen is one Bool.

### priority

`let priority: DropletHUDPriority`

Priority band.

### showsExpandedContent

`var showsExpandedContent: Bool { get }`

Whether the host should draw the card rather than the strip.

Both have to be true: a request that says it is expanded but ships no card is a strip, not an empty card.
