---
title: "ShelfWidgetDynamicLayoutProviding, DroppyKit"
description: "Optional live-layout refinement for a shelf widget provider."
canonical: "https://getdroppy.app/docs/droppykit/api/shelf-widget-dynamic-layout-providing"
last-updated: "2026-09-09"
---

# ShelfWidgetDynamicLayoutProviding

Optional live-layout refinement for a shelf widget provider.

`@MainActor protocol ShelfWidgetDynamicLayoutProviding : ShelfWidgetProviding`

This deliberately lives beside [`ShelfWidgetProviding`](https://getdroppy.app/docs/droppykit/api/shelf-widget-providing) instead of adding a requirement to it: an already compiled droplet keeps the original protocol witness table, while a newer product can opt into a host refresh when product-owned content changes its requested canvas. The host still owns the layout envelope and clamps every returned trait before using it.

## Properties

### shelfWidgetLayoutInvalidationPublisher

`@MainActor var shelfWidgetLayoutInvalidationPublisher: AnyPublisher<ShelfWidgetID, Never> { get }`

Emits after a product-owned layout input changes. The value identifies the widget whose traits the host should re-read; it carries no product model data across the bundle boundary.

## Methods

### currentLayoutTraits(for:)

`@MainActor func currentLayoutTraits(for id: ShelfWidgetID) -> ShelfWidgetLayoutTraits?`

The current layout traits for one declared widget, or `nil` to keep its descriptor's static traits. Callers ask at explicit pre-size and render edges; this must be cheap and must not create views.

No [`ShelfWidgetContext`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context) reaches this call, so a height computed to fit the content exactly cannot tell which [`contentInsets`](https://getdroppy.app/docs/droppykit/api/shelf-widget-context#content-insets) it will get: budget the 16pt the 18pt card corner takes, the larger of the two (a solo island card takes none).
