RemoveNot Applicable
Tooltip V2 Component link

A small floating callout anchored to a target with a directional pointer; ships in eight pointer positions.

Superseded by Tooltip
Superseded by Tooltip. The version suffix is gone, the four pointer booleans became a single Placement enum, the leading placeholder and CTA moved into ⤷ AssetSlot and ⤷ ActionSlot, and the raster pointer and close image were replaced with a vector and a DS icon instance. Kept as a record of the assessment that drove the consolidation.
In Context

Tooltips sit over a target element (tab, button, icon, card) with a pointer aimed at the thing they describe.

Wallet Next
Live Preview
Header
Description goes here. This is the second sentence. The third sentence.
Next
Content
header
description
icon
cta
Placement
pointer
DS Health
Reusable
Partial
Covers the main in-product tooltip pattern across onboarding, tips, and nudges. But because 3 siblings exist for 3 skins, consumers have to hunt for the right one — the primitive is fragmented. C1
Self-contained
Warn
Surface, type, and spacing bind to main/nudge/* + space/* tokens. But the pointer arrow is a raster image (4 rotated copies of one shape) and the leading icon is a gray placeholder circle, not a slot. C6
Consistent
Warn
Component is named Tooltip V2 — version suffixes don't belong in production DS names. Pointer direction is 4 separate booleans rather than one enum, letting consumers set nonsensical combinations (e.g. all 4 pointers on). C2
Composable
Warn
No Figma Slot for leading icon or body content. CTAs are baked Button instances that re-implement pill padding rather than composing the Button component consistently across variants (one variant uses px-16 / py-12, another uses px-8 / py-6). C4
Behavior
State iOS Android Figma Property Notes
Show / hide Yes Yes Not annotated Expected: fade + slight scale-in anchored on the pointer side.
Tap close (X) Yes Yes Close layer Dismiss icon is present in markup but not wired to a property or interaction. Contract should be explicit.
Tap outside N/A N/A Not defined Standard tooltip contract — tap-outside dismisses. Should be documented on the component.
Primary CTA Yes Yes CTA=one / two Advances in onboarding or performs the tip's primary action.
Secondary CTA Yes Yes CTA=two "Back" in onboarding; "Learn more" in tips.
Pressed / Focused N/A N/A Not built CTAs and close have no pressed/focused treatment on the tooltip component itself. Inner Button instances handle their own press, but close + the tooltip surface do not.
Installation Planned API

iOS — Swift Package Manager

// In Xcode: File → Add Package Dependencies
"https://github.com/AY-Org/eb-ds-ios"

Android — Gradle (Kotlin DSL)

dependencies {
    implementation("com.eastblue.ds:tooltip:1.0.0")
}
Property Mapping
Figma PropertySwiftUICompose
3 sibling components 1 component: Tooltip EBTooltip
(sibling = appearance) appearance: .default / .onboarding / .translucent .ebAppearance(.default / .onboarding / .translucent)
pointerTop/Right/Bottom/Left: Bool × 4 placement: .top / .right / .bottom / .left / .none arrowEdge: Edge
header: Bool + text baked title: String? title: String?
description: Bool + text baked body: String? (or content slot) body: String?
icon: Bool (gray placeholder) leading (Slot) @ViewBuilder leading
Close image asset (always) hasDismiss: Bool dismissible: Bool
cta: none / one / two cta: .none / .primary(String) / .pair(back, next) primary / secondary: TooltipAction?
outlineButton: Bool (absorbed into cta.pair)
(not modeled) hasArrow: Bool arrow: Bool
(not modeled) onDismiss onDismiss: () -> Void
SwiftUI
ios/Components/Tooltip/EBTooltip.swift
Jetpack Compose
android/components/tooltip/EBTooltip.kt
Usage Snippets Planned API
Usage
// Simple tip — title + body, pointer below
EBTooltip(
    title: "Quick transfers",
    body: "Tap here to send money to recent contacts.",
    placement: .bottom
)
.onDismiss { showTip = false }

// Walkthrough step — two CTAs
EBTooltip(
    title: "Step 2 of 4",
    body: "Review your balance before confirming.",
    placement: .top,
    cta: .pair(back: "Back", next: "Next")
)
.ebAppearance(.onboarding)

// Rich — custom leading slot
EBTooltip(title: "Welcome", body: "Tap a card to begin.") {
    Image(systemName: "sparkles")
}

// iOS 17 + Tips — recommended for onboarding flows
.popoverTip(quickTransferTip)
// Simple tip
EBTooltip(
    title = "Quick transfers",
    body = "Tap here to send money to recent contacts.",
    placement = EBTooltipPlacement.Bottom,
    onDismiss = { showTip = false }
)

// Walkthrough step — two CTAs, onboarding skin
EBTooltip(
    title = "Step 2 of 4",
    body = "Review your balance before confirming.",
    placement = EBTooltipPlacement.Top,
    appearance = EBTooltipAppearance.Onboarding,
    primaryAction = TooltipAction("Next", onClick = { advance() }),
    secondaryAction = TooltipAction("Back", onClick = { rewind() })
)

// Custom leading slot
EBTooltip(
    title = "Welcome",
    body = "Tap a card to begin.",
    leading = { Icon(Icons.Default.AutoAwesome, contentDescription = null) }
)

// Material 3 PlainTooltip equivalent
PlainTooltip { Text("Shortcut") }
Accessibility
RequirementiOSAndroid
Role + focus Announce tooltip as .accessibilityAddTraits(.isModal) when hasDismiss = true — otherwise role .staticText. semantics { role = Role.Popup } on the container; TalkBack focuses it on appear.
Close control Wrap close as a Button with accessibilityLabel "Dismiss tip" and 44×44 hit target. IconButton with contentDescription = "Dismiss tip"; 48×48dp minimum.
Dismiss-outside Respect UIAccessibility.isVoiceOverRunning — do not auto-dismiss tooltips while VO is active. Do not auto-dismiss while TalkBack is active; hold the tooltip until the user explicitly moves on.
Reduce motion Respect UIAccessibility.isReduceMotionEnabled — skip the scale-in animation; fade only. Respect Settings.Global.TRANSITION_ANIMATION_SCALE — fade only when user has motion reduced.
Combined label Read title + body + "Dismiss" as one phrase; avoid reading pointer. Same; set mergeDescendants = true on the container.
Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Requires Rework 3 sibling components for one primitive. Close uses a raw image asset inside a generic frame rather than an icon/close instance.
C2 Variant & Property Naming Requires Rework Version suffix in the component name (Tooltip V2). Pointer direction is 4 booleans instead of one enum.
C3 Token Coverage Ready Surface, border, label, description, and CTA colors bound to main/nudge/* and main/button/* tokens. Spacing via space/*.
C4 Native Mappability Requires Rework Maps cleanly once pointer booleans → placement enum and sibling skins → appearance enum. CTA padding inconsistencies block a 1:1 Button reuse.
C5 Interaction State Coverage Requires Rework No Pressed / Focused on close. No lifecycle (appearing / dismissing) annotated. Close isn't wired to a dismiss property.
C6 Asset & Icon Quality Requires Rework Pointer is 4 raster images (one per edge). Leading icon is a gray placeholder circle. Close is an image asset.
C7 Code Connect Linkability Not Mapped Blocked on consolidation + enum conversion + slot adoption. Mapping today's shape would cement the wrong schema.
Variants Inventory (8 total)

4 booleans and one 3-value enum yield 8 shipped variants out of a 24-cell theoretical matrix (CTA (3) × Icon (2) × Description (2) × Header (2) = 24). Only the 8 meaningful combinations are exposed. Pointer direction is 4 additional booleans outside the variant matrix.

#CTAIconDescriptionHeaderDimensionsNode
1oneyesyesyes359 × 18170:14907
2onenoyesyes359 × 1557977:12260
3noneyesyesyes359 × 13770:14903
4nonenoyesyes359 × 11970:14902
5nonenonoyes359 × 7970:14900
6nonenoyesno359 × 9270:14901
7twonoyesno359 × 13670:14905
8onenoyesno359 × 13670:14906
2.0.0 — August 2026Major
Consolidated into Tooltip · node 6295:79647
Superseded by TooltipTooltip V2 was consolidated into the unified Tooltip set (node 6295:79647) alongside its two siblings. Verdict changed to Remove; open issues and recommendations cleared, since they are resolved on the successor. Resolved
Consolidated
1.0.0 — April 2026Major
Initial Assessment · node 70:14908
Verdict: Restructure — Consolidate 3 sibling Tooltip components; drop the V2 suffix; replace 4 pointer booleans with one placement enum; replace raster pointer with vector; replace placeholder icon with a Figma Slot. Open
Architecture
C1 — 3 siblings for 1 primitive — Tooltip V2, Onboarding - Tooltip, Tooltip Blurred and Transparent. Merge via appearance enum. Open
C1
C2 — Version suffix in nameTooltip V2 shouldn't exist in production; no V1 surfaces in the file. Open
C2
C2 — Pointer is 4 booleans — Replace pointerTop/Right/Bottom/Left with a single placement enum. Open
C2
C4 — CTA padding drift — Same XSmall Button, three different paddings across variants. Normalize. Open
C4
C5 — No dismiss/focus states — Close is decorative; Pressed / Focused / Lifecycle not modeled. Open
C5
C6 — Raster pointer + placeholder icon — 4 raster images for the pointer; gray circle for the leading icon. Vector + slot. Open
C6
C7 — Code Connect — Blocked on the architectural changes above. Open
C7
Tokens ✓ — Surface / border / label / description / CTA colors all bound to main/nudge/* and main/button/*. Spacing via space/*. Noted
Praise