A directional tooltip used in onboarding overlays, with a pointer, header, description, and dismiss control.
Fold into the unified Tooltip; "Onboarding -" prefix is misleading (no walkthrough content)
This component, Tooltip V2, and Tooltip Blurred and Transparent model the same primitive with slightly different shapes. Merge into one
Tooltip with placement: .top | .right | .bottom | .left (the only axis this sibling ships), appearance: .default | .onboarding | .translucent, hasDismiss, and an optional content/CTA body. Replace the 4 raster pointers with one vector and the raw close image with an icon/close instance. Once merged, rename the sibling that truly supports walkthroughs (with step indicator + Next/Skip) to carry the .onboarding appearance — or drop the name entirely.In Context
A dismissible tip anchored to a feature element — commonly rendered during first-time user education, feature discovery, and coach-mark flows.
Live Preview
Header
Description goes here
Placement
pointer
DS Health
Reusable
Warn
Works as a dismissible tip anchored to any target. But the "Onboarding -" prefix steers consumers toward walkthroughs it can't support (no step indicator, no Next/Skip). Misleading name fragments the primitive. C1
Self-contained
Warn
Surface, type, and spacing bind to
main/nudge/* + space/* tokens — shares the collection with Tooltip V2. But the pointer arrow is 4 raster copies of one shape, and the close is an image asset rather than a DS icon instance. C6Consistent
Warn
Pointer is modeled as a single enum here, but Tooltip V2 models the same concept as 4 booleans. Siblings should not disagree on the shape of a shared axis. C2
Composable
Fail
No Figma Slot for body content. No way to add an icon, an avatar, or a CTA — consumers who need those must switch components entirely. The primitive is closed. 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 but not wired to an interactive property. Close is an image asset, not a button instance. |
| Tap outside | N/A | N/A | Not defined | Standard tooltip contract — tap-outside dismisses. Should be documented on the component. |
| Primary CTA | N/A | N/A | Not built | Despite the "Onboarding" name, no CTA is provided. Consumers must switch to Tooltip V2 for any advance/skip control. |
| Pressed / Focused on close | N/A | N/A | Not built | Close is a raw image; no pressed / focused treatment and no hit target metadata. |
Open Issues
- Name implies walkthrough content that isn't shipped.
Onboarding - Tooltiphas no step indicator, no Next/Skip/Back CTAs, no progress dots, no illustration slot — it's just header + description + close. The prefix misleads consumers. Either rename toTooltip / Placementand fold into the unified Tooltip, or add the actual onboarding axes (step indicator, Next/Skip) before keeping the name. C1 · Layer Structure & Naming - Three sibling Tooltip components for one primitive.
Tooltip V2(70:14908), this component (51:17066), andTooltip Blurred and Transparent(49:335349) all model the same floating popover with slightly different shapes. Collapse into oneTooltipwithappearance+placement. C1 · Layer Structure & Naming - Pointer schema disagrees with sibling. Onboarding - Tooltip models pointer direction as one
pointerenum (correct), but Tooltip V2 models the same concept as 4 independent booleans. Siblings in the same family should never disagree on the shape of a shared axis. C2 · Variant & Property Naming - Pointer triangle is a raster asset. 4 separate image fills (
imgPointer,imgPointer1,imgPointer2,imgPointer3) for what should be one vector shape rotated per direction. Replace with a single vector triangle; rotation handled by theplacementenum. C6 · Asset & Icon Quality - Close (X) is an image asset, not a DS icon instance. The dismiss control uses
imgShapeFullinside a generic "Close" frame rather than an instance of the DS'sicon/close. Hides the icon from a11y labeling and token updates, blocks Code Connect from seeing it as a real control. C1 · Layer Structure & Naming - No body or CTA slot. There is no way to add a leading icon, an illustration, a step indicator, or a CTA. Any consumer that needs those must abandon this component for Tooltip V2 — defeating the point of a dedicated "Onboarding" sibling. C4 · Native Mappability
- No dismiss / show states modeled. Close button is decorative; no Pressed / Focused state on the dismiss control. No appearing / dismissing lifecycle documented. C5 · Interaction State Coverage
- Code Connect mappings not registered. Blocked on the family consolidation. Mapping today's 3-sibling shape to native would cement the wrong schema. C7 · Code Connect Linkability
Design Recommendations
- Fold the 3 Tooltip siblings into one component. New schema:
placement: .top | .right | .bottom | .left(this sibling's only axis),appearance: .default | .onboarding | .translucent,hasArrow: Bool,hasDismiss: Bool,cta: .none | .primary | .primaryAndSecondary, and aleadingslot. This sibling's 4 variants collapse into theplacementaxis of the.defaultappearance — no dedicated component needed. Family - Rename or retire the "Onboarding -" prefix. The prefix should either be reserved for a sibling that actually ships onboarding affordances (step indicator, Next/Skip, Back) — in which case this component doesn't qualify — or dropped entirely in favor of an
appearance: .onboardingenum on the unified Tooltip. Today's name promises content it doesn't deliver. Rename - Replace the 4 raster pointers with one vector triangle. Today there are 4 separate rasters (top/right/bottom/left). One vector shape, rotated per
placement, fills the same role with zero asset burden, scales cleanly, and picks up surface + border token updates automatically. Asset - Instance-swap the close to
icon/close. Use the canonical DS close-icon instance rather than an inlineimgShapeFull. Gets you token-driven color, a11y labeling, and press-state handling for free. Composition - Adopt a content slot for body + optional CTA. The current closed shape (header + description + close, nothing else) is the reason this sibling exists. Adopt the unified Tooltip's content slot and this component disappears into the single source of truth. Slot
- Add Pressed / Focused on the close control. Once the close becomes an icon-button instance rather than an image, states follow the canonical Button/Icon pattern. State
- Document the dismiss contract + lifecycle. Add a description on the component: "Tap the close X or tap outside to dismiss. Tooltip appears with fade + slight scale from the pointer anchor; dismisses with reverse." Close the gap between designer intent and dev implementation. Docs
Styles
Pointers
DES DEV
Pointer triangle indicates target placement. Flip the pointer control in the demo panel to see top / right / bottom / left positions.
Header
Description goes here
Properties
pointer
Properties
pointer top
Colors
Surface #FFFFFF
Border #E5EBF4
Header #0A2757
Description #6780A9
Close icon #0A2757
Layout
Width 296px (max)
Padding 16 × 12
Border radius 6px
Pointer size 12 × 8
Typography
Header style Primary/Headlines/Block
Header font Proxima Soft Bold · 18 / 23 · +0.25
Description style Secondary/Bold/Caption
Description font BarkAda Semibold · 12 / 18
Colors by State
| Role | Token | Default |
|---|---|---|
| Surface | main/nudge/color/primary/bg | #FFFFFF |
| Border | main/nudge/color/primary/border | #E5EBF4 |
| Header label | main/nudge/color/primary/label | #0A2757 |
| Description | main/nudge/color/primary/description | #6780A9 |
| Close icon | main/nudge/color/primary/icon-close | #0A2757 |
| Shadow | elevation/app/shadow-low | #020E22 · 6 % |
| Pointer triangle | — | raster (4 images) |
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 Property | SwiftUI | Compose |
|---|---|---|
| Onboarding - Tooltip (this) | Tooltip · appearance: .default | EBTooltip().ebAppearance(.default) |
| pointer: top / right / bottom / left | placement: .top / .right / .bottom / .left | arrowEdge: Edge |
| header (baked text) | title: String? | title: String? |
| description (baked text) | body: String? (or content slot) | body: String? |
| close (image asset, always shown) | hasDismiss: Bool | dismissible: Bool |
| (not modeled) | cta: .none / .primary / .pair | primary / secondary: TooltipAction? |
| (not modeled) | leading (Slot) | @ViewBuilder leading |
| (not modeled) | onDismiss | onDismiss: () -> Void |
SwiftUI
ios/Components/Tooltip/EBTooltip.swift
Jetpack Compose
android/components/tooltip/EBTooltip.kt
Usage Snippets Planned API
Usage
// Equivalent of today's "Onboarding - Tooltip · pointer=bottom" EBTooltip( title: "Quick transfers", body: "Tap here to send money to recent contacts.", placement: .bottom ) .onDismiss { showTip = false } // pointer=right · same appearance, placement flipped EBTooltip( title: "Your balance", body: "Tap to reveal or hide.", placement: .right )
// Equivalent of today's "Onboarding - Tooltip · pointer=bottom" EBTooltip( title = "Quick transfers", body = "Tap here to send money to recent contacts.", placement = EBTooltipPlacement.Bottom, onDismiss = { showTip = false } ) // pointer=right EBTooltip( title = "Your balance", body = "Tap to reveal or hide.", placement = EBTooltipPlacement.Right )
Accessibility
| Requirement | iOS | Android |
|---|---|---|
| Role + focus | Announce as .accessibilityAddTraits(.isModal) when dismissible; VoiceOver moves focus to the tooltip on appear. | semantics { role = Role.Popup }; TalkBack focuses the tooltip container on appear. |
| Close control | Wrap close as a Button with accessibilityLabel "Dismiss tip" and 44×44 hit target (current 24 × 24 is below minimum). | IconButton with contentDescription = "Dismiss tip"; 48×48 dp minimum (current hit area is ~24 × 24 dp). |
| Dismiss-outside | Do not auto-dismiss while VoiceOver is active — hold until user explicitly moves on. | Do not auto-dismiss while TalkBack is active. |
| Reduce motion | Respect UIAccessibility.isReduceMotionEnabled — fade only, skip scale-in. | Respect Settings.Global.TRANSITION_ANIMATION_SCALE — fade only when motion reduced. |
| Combined label | Read title + body + "Dismiss" as one phrase; avoid reading pointer. | mergeDescendants = true on the container. |
Criteria Scorecard
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Requires Rework | "Onboarding -" prefix misleads — component ships no walkthrough content. 3 sibling Tooltip components for one primitive. Close uses a raw image inside a generic "Close" frame. |
| C2 | Variant & Property Naming | Needs Refinement | Pointer is correctly modeled as one enum here (cleaner than Tooltip V2's 4 booleans) — but siblings should agree on the shape of the shared axis. |
| C3 | Token Coverage | Ready | Surface, border, label, description, close icon, shadow all bound to main/nudge/* / elevation/*. Spacing via space/*. Radius via radius/radius-2. |
| C4 | Native Mappability | Requires Rework | Closed shape — no slot for body content or CTA. Maps cleanly to native only after consolidation into the unified Tooltip with content slot + cta axis. |
| C5 | Interaction State Coverage | Requires Rework | No Pressed / Focused on close. No appearing / dismissing lifecycle annotated. Close isn't wired to a dismiss property. |
| C6 | Asset & Icon Quality | Requires Rework | Pointer is 4 raster images (one per direction). Close is an image asset (imgShapeFull) rather than an icon/close instance. |
| C7 | Code Connect Linkability | Not Mapped | Blocked on consolidation. Mapping today's sibling component would cement the wrong schema. |
Variants Inventory (4 total)
One axis: pointer (4 values) = 4 variants. Content (header / description / close) is fixed across all variants.
| # | Pointer | Dimensions | Pointer asset | Node |
|---|---|---|---|---|
| 1 | top | 336 × 90 | imgPointer | 51:17065 |
| 2 | bottom | 336 × 89 | imgPointer1 | 51:17063 |
| 3 | left | 348 × 78 | imgPointer2 | 51:17062 |
| 4 | right | 348 × 78 | imgPointer3 | 51:17064 |
1.0.0 — April 2026Major
Initial Assessment · node 51:17066
Verdict: Consolidate — Fold into the unified Tooltip as
Architectureappearance: .default with the placement axis. The "Onboarding -" prefix is misleading (no walkthrough content ships). OpenC1 — Misleading name — No step indicator, no Next/Skip/Back CTAs, no progress dots. Component is not onboarding-specific. Open
C1C1 — 3 siblings for 1 primitive — Tooltip V2, Onboarding - Tooltip, Tooltip Blurred and Transparent. Merge via
C1appearance + placement. OpenC2 — Pointer schema disagrees with sibling — This sibling uses one enum; Tooltip V2 uses 4 booleans. Family members should agree on the shape of a shared axis. Open
C2C4 — No slot for body or CTA — Closed shape forces consumers to switch to Tooltip V2 for anything richer than header + description. Open
C4C5 — No dismiss/focus states — Close is a raw image; Pressed / Focused / Lifecycle not modeled. Open
C5C6 — Raster pointer + raw close — 4 raster images (one per direction). Close is an image asset rather than
C6icon/close. Vector + icon instance. OpenC7 — Code Connect — Blocked on consolidation. Open
C7Tokens ✓ — Surface / border / label / description / close / shadow all bound to
Praisemain/nudge/* and elevation/*. Spacing via space/*. Noted