A full-viewport scrim used to dim background content behind sheets, modals, and tooltips. Three strength tiers.
How the overlay appears in a real product screen — it dims the Tree Details page behind a modal, so the plant confirmation and its Okay button stand out.

dim layer scales exactly with the instance — verified rendering at 640, 761, 826 and 932.Weak · Default · Strong) under a single Strength property. Naming no longer implies a missing sibling.Content → Overlay → Floating surface — so teams no longer have to infer it.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Show / hide | Yes | Yes | Not defined | Fades with the presentation transition of its owning surface. |
| Tap to dismiss | Yes | Yes | Not annotated | Contract: tap-scrim dismisses unless surface is marked modal. |
| Scroll lock | N/A | N/A | Handled by surface | Owning sheet/dialog locks background scroll on mount. |
| Focus / a11y | Yes | Yes | Implicit | Scrim itself is not focusable — owning surface traps focus. |
-
Strengthproperty added. v2.0:Weak(24%) ·Default(40%) ·Strong(56%), replacing the single 56% variant whose-strongtoken name implied a missing sibling. (C2) C2 · Variant & Property Naming - Default frame resized and verified at scale. v2.0: 360×640 →
360×800, with thedimlayer tracking the instance exactly at every size — verified across five placements from 640 to 932. (C4) C4 · Native Mappability -
Containerwrapper removed. v2.0: Structure simplified toCOMPONENT → dim, one layer deep. (C1) C1 · Layer Structure & Naming - Tap-to-dismiss contract settled. v2.1: The behaviour is documented on this page — tap outside dismisses the surface above unless that surface is modal, in which case dismissal requires an explicit action. Layer order is
Content → Overlay → Floating surface. (C5 · Docs) C5 · Interaction State Coverage - Strength tiers bound to their own tokens. v2.2: Confirmed by the component owner — each tier now resolves through its own semantic token rather than a shared fill with a hand-set opacity, so a theme change is one edit and developers no longer copy three loose alpha values. Not independently verifiable from the assessment tooling, which cannot read variable bindings: the paint still reports as
#020E22at 24/40/56% opacity either way. (C3 · Token) C3 · Token Coverage - "Don't Use" label clarified. v2.2: Closed by owner confirmation — the label belongs to the enclosing Figma section, which is a working container for in-progress material, not a directive against the component. The
Overlayset at4465:20631inside it is current and is what this page documents. (C1) C1 · Layer Structure & Naming - Cross-system naming documented. v2.2: Closed — the team keeps Overlay. Other systems name this primitive differently: Scrim (Material 3), Backdrop (Fluent, Polaris), Mask (Ant), Blanket (Atlassian), Underlay (Spectrum). Recorded here so anyone cross-referencing another system finds the equivalent rather than assuming a gap. (Docs) C1 · Layer Structure & Naming
Component Playground
Layout
VStack
Typography
Colors
iOS — Swift Package Manager
.package(url: "https://github.com/AY-Org/eb-ds-ios", from: "1.0.0")
Android — Gradle (Kotlin DSL)
implementation("com.eastblue.ds:overlay:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.overlay.*
Strength is the set’s only property; each variant is a single `dim` rectangle bound to its own token (v2.x). Presentation, dismissal and the content above the scrim are platform concerns and have no Figma property.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| Strength — Weak, Default, Strong | .ebStrength(.weak / .default / .strong) | strength = EBOverlayStrength.Weak / Default / Strong |
EBOverlay(isPresented: $showSheet)
.ebStrength(.weak) EBOverlay(
visible = showSheet,
onDismiss = { },
strength = EBOverlayStrength.Weak
) EBOverlay(isPresented: $showSheet)
.ebStrength(.default) EBOverlay(
visible = showSheet,
onDismiss = { },
strength = EBOverlayStrength.Default
) EBOverlay(isPresented: $showSheet)
.ebStrength(.strong) EBOverlay(
visible = showSheet,
onDismiss = { },
strength = EBOverlayStrength.Strong
) | Requirement | iOS | Android |
|---|---|---|
| Modal scope | .accessibilityViewIsModal(true) on the surface above the scrim so VoiceOver ignores what is dimmed. | ModalBottomSheet / Dialog scope TalkBack to the surface. |
| Tap to dismiss | The scrim is a Button labelled "Dismiss"; .accessibilityAction(.escape) also dismisses. | Scrim click calls onDismissRequest; back press dismisses. |
| Not announced | .accessibilityHidden(true) on the dim rectangle itself. | clearAndSetSemantics on the scrim. |
| Reduce transparency | Strong is the floor when Reduce Transparency is on. | Same — use Strong when the user reduces transparency. |
Do
Use Default under sheets and dialogs.
Don't
Don’t use Weak under a dialog that needs focus.
Do
Use Strong over imagery or busy screens.
Don't
Don’t stack two overlays — one scrim per surface.
Do
Size the scrim to the window, not the sheet.
Don't
Don’t inset the scrim — it covers the safe areas too.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | One dim rectangle per variant — read on 4465:20632. |
| C2 | Variant & Property Naming | Ready | Strength — Weak, Default, Strong. |
| C3 | Token Coverage | Ready | No text layers. The three fills resolve to #020E22 at 24 / 40 / 56%; variable bindings are not readable with the plugin — confirm in Dev Mode. |
| C4 | Native Mappability | Ready | One enum — maps onto EBOverlay over the platform scrim. |
| C5 | Interaction State Coverage | Ready | Tap-to-dismiss contract settled (v2.x); no visual states beyond the three strengths. |
| C6 | Asset & Icon Quality | Not Applicable | No icons or images. |
1 Strength × 3 values = 3 variants
| Strength | Node | Dimensions |
|---|---|---|
| Weak | 4465:20549 | 360 × 800 |
| Default | 4465:20632 | 360 × 800 |
| Strong | 4465:20634 | 360 × 800 |
Strength value, each drawn over the same preview stage; the three opacities verified on 4465:20549, 4465:20632 and 4465:20634. Padding, gap, alignment and colour tokens are not readable with the plugin and stay —.Strength schema. Property Mapping trimmed to the one Figma property, Usage Snippets per Strength, Guidelines added, Variants Inventory on the three live nodes.Strength, Surface and Background as three properties. Figma has one. The backdrop controls implied a schema the component does not have, and are now fixed scenery in the preview rather than configurable properties. Documentedweak / default / strong → Weak / Default / Strong per §5, and the default moved from Strong to Default. DocumentedcodeConnect was an empty array. Four rows now, with asset linkability marked Not Applicable: the component is a single rectangle. DocumentedContent → Overlay → Floating surface. ResolvedStrength property added — Weak (24%) · Default (40%) · Strong (56%), replacing the single 56% variant whose -strong token name implied a sibling that did not exist. Resolveddim layer tracking the instance exactly at every size, verified across five placements from 640 to 932. ResolvedContainer wrapper removed — structure simplified to COMPONENT → dim, one layer deep. Resolved47:329691 to 2026 Working File 4465:20631. Section is still marked (Don't Use) — not yet published. DocumentedStrength = Weak (24%) | Default (40%) | Strong (56%) added, replacing the single 56% variant. Shipped as three tiers rather than the two proposed at baseline. Resolved360×800; dim tracks the instance exactly, verified at 640 / 761 / 826 / 932 across five placements. ResolvedContainer wrapper removed; structure is now COMPONENT → dim. Resolvedstrength enum. Openstrong (56%) exposed, token name implies a standard counterpart. Open