KeepNeeds Refinement
Callout Component link

A compact attention strip with neutral, info, warning, or danger intent, optional description, and an optional leading icon.

Rebuilt — intent enum and slots landed
The rebuild resolved every structural issue: renamed to Callout, type expanded to a 5-value intent enum (Information / Default / Warning / Error / Success), the redundant label + label size axes collapsed into Content × Size, and real Figma Leading Slot / Trailing Slot added. 45 variants with no invalid cells. Stateless by design — Callout is a display strip; interactivity lives in the Trailing Slot. Only Code Connect registration and the token rename remain.
In Context

Appears beneath form fields, inside modals, or between screen sections — to clarify what happens next, flag a soft warning, or offer supplemental instructions that don't rise to Alert-level severity.

Live Preview
Add title here
This is the first sentence. This is the second sentence. This is the third sentence. This is the fourth sentence. This is the fifth sentence.
Properties
label
label size
description
type
DS Health
Reusable
Pass
Covers the full intent range — Information, Default, Warning, Error, Success — so consumers no longer reach for the heavier Alert just to show a warning. Three sizes (Large / Small / XSmall) and three content shapes (Default / Description Only / Header Only) cover inline use in forms, modals, and flows.
Self-contained
Pass
Carries its own container, title, description, and per-intent tokens across all five intents. Both the leading icon and trailing action are now real Figma slots rather than missing affordances.
Consistent
Pass
Three orthogonal props — Type × Size × Content = 45 variants with no invalid cells. The old label + label size pair that encoded one concept across two properties is gone, and type is a full intent enum rather than a two-value stub.
Composable
Pass
Named Leading Slot (24 × 24, radius 99) and Trailing Slot let consumers compose an icon and an inline action without forking the component. Both map to @ViewBuilder / @Composable slots on native.
Behavior
State iOS Android Figma Property Notes
Default (neutral) Yes Yes Type=Default Grey-blue bg #F6F9FD, border #E5EBF4, subtext #6780A9. Ambient hints with no intent.
Information Yes Yes Type=Information Light blue bg #E5F1FF, border #D2E5FF, title #072592. Helpful context.
Warning Yes Yes Type=Warning Amber bg #FFF9EB, border #F9E39A, subtext #966F0B. Added in the rebuild — previously required the heavier Alert.
Error Yes Yes Type=Error Red bg #F8E6E6, border #F4C7C9, subtext #D61B2C. Added in the rebuild.
Success Yes Yes Type=Success Green bg #E7F8F0, border #CAF2E0, subtext #035E50. Added in the rebuild.
Content composition Yes Yes Content Default shows title + description, Header Only shows the title alone, Description Only the body alone. Composes with every intent and size.
Pressed / Disabled N/A N/A Not modelled by design. Callout is a display strip, not an interactive control — any interactivity lives in whatever occupies the Trailing Slot, which carries its own states.
Issues
  • Code Connect mappings not registered. The naming, intent enum, slot, and content-axis blockers are all resolved in the rebuild. Registration is now unblocked but the SwiftUI / Compose mappings are not yet wired, and the native component does not exist — snippets remain a Planned API. C7 · Code Connect Linkability
  • v2.0: Renamed Contextual HelpCallout — the internal jargon is gone and the name matches external precedent (Radix Themes uses the same term for an icon + short-message strip). (C1)
  • v2.0: type expanded from a two-value stub into a full 5-value intent enum — Information / Default / Warning / Error / Success. (C2)
  • v2.0: Redundant label + label size axes collapsed — content composition is now one Content axis (Default / Description Only / Header Only) with Size (Large / Small / XSmall) as a separate orthogonal prop. Full 5 × 3 × 3 = 45 matrix, no invalid combinations. (C2)
  • v2.0: Leading icon slot added — a real Figma Leading Slot (24 × 24, radius 99) in every variant, so consumers can drop in any icon or avatar. (C4)
  • v2.0: Trailing action slot added — a real Figma Trailing Slot in every variant for a dismiss affordance or inline action. (C4)
  • v2.0: Empty leading slot with no per-intent icon defaults confirmed intentional — the slot is left for the consumer to fill rather than shipping a default icon per intent. (C6)
  • v2.0: Absence of interaction states confirmed intentional — Callout is a display strip, not an interactive control. Any interactivity lives in whatever occupies the Trailing Slot, which carries its own states. (C5)
Recommendations
  • Rename main/contextual-help/color/info/*main/callout/info/*. Token names should follow the component name now that the rename has landed. Deliberately deferred until native handoff so consuming files do not churn twice — still outstanding. Token
  • Document the Callout vs Alert vs Subtext Message vs Tooltip decision tree. Designers conflate these four because the naming overlaps. Publish a one-pager: Subtext (field helper), Callout (inline display strip, soft intent, no CTA), Alert (persistent status block with a title and optional action), Tooltip (transient, anchored). The clearest tell is the action — if it has a CTA or title hierarchy it is an Alert, not a Callout. Docs
  • Rename Contextual HelpCallout. v2.0: Applied — the component set is now named Callout, dropping the internal jargon and matching external precedent. Rename
  • Collapse label + label size into one axis. v2.0: Applied, and cleaner than proposed — instead of a single labelSize enum, content composition is now Content (Default / Description Only / Header Only) with Size (Large / Small / XSmall) as a separate orthogonal prop. No invalid cells across the full 45-variant matrix. Property
  • Expand type into a proper intent enum. v2.0: Applied, and one value beyond the recommendation — Information / Default / Warning / Error / Success, replacing the two-value stub. Property
  • Add a leading-icon slot. v2.0: Applied — a real Figma Leading Slot (24 × 24, radius 99) ships in every variant. The per-intent default icons from the original recommendation were deliberately not added; the slot is left for the consumer to fill. Slot
  • Add a trailing action slot. v2.0: Applied — a real Figma Trailing Slot ships in every variant for a dismiss affordance or inline action. Slot
  • Add Pressed and Disabled states. v2.0: Reviewed and closed as not needed — Callout is a display strip, not an interactive control. Any interactivity lives in whatever occupies the Trailing Slot, which carries its own states. State
Types
Default
DES DEV

Compact attention strip. Flip Type / Label / Label size / Description to walk through every variant.

Properties
Type
Label
Label Size
Description
Properties
Type Default
Label yes
Label size Default
Description yes
Colors
Surface #F6F9FD
Border #E5EBF4
Label #445C85
Description #6780A9
Layout
Padding 12 × 12
Border radius 6
Border 1px solid
Gap 8
Typography
Label style Primary/Label/Base
Label font Proxima Soft Bold · 16 / 16 · +0.25
Description style Secondary/Bold/Base
Description font BarkAda Semibold · 14 / 20
Colors by Type

All colors bound to main/contextual-help/color/* tokens (target after rename: main/callout/*). No appearance modes. No Pressed or Disabled state defined.

Role Token TOKENVALUE
Default bg main/contextual-help/color/default/bg #F6F9FD
Default border main/contextual-help/color/default/border #E5EBF4
Default label main/contextual-help/color/default/label #445C85
Default description main/contextual-help/color/default/description #6780A9
Information bg main/contextual-help/color/info/bg #E5F1FF
Information border main/contextual-help/color/info/border #D2E5FF
Information label main/contextual-help/color/info/label #072592
Information description main/contextual-help/color/info/description #6780A9
Success — (missing)
Warning — (missing)
Error — (missing)
Pressed — (missing)
Disabled — (missing)
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:feedback:1.0.0")
}

Import

import EastBlueDS  // SwiftUI
import com.eastblue.ds.feedback.*  // Compose

Package not yet published. Names reflect the proposed rename (EBCallout, not EBContextualHelp).

Property Mapping

Assumes the recommended architecture: single labelSize enum (replacing label + label size), full 4-value intent enum (replacing type), plus an optional leading icon and trailing action slot.

Figma PropertySwiftUICompose
label (yes/no) + label size (small/default/no) labelSize: EBCalloutLabelSize = .none labelSize: EBCalloutLabelSize = None
Label text title: String? title: String? = null
description (yes/no) description: String? description: String? = null
type=default | information .ebIntent(.info / .success / .warning / .error) intent: EBCalloutIntent
— (missing) leadingIcon: Image? leadingIcon: @Composable (() -> Unit)?
— (missing) trailingAction: (() -> some View)? trailingAction: @Composable (() -> Unit)?
— (missing) .disabled(true) enabled: Boolean = true
SwiftUI
ios/Components/Feedback/EBCallout.swift
Jetpack Compose
android/components/feedback/EBCallout.kt
Usage Snippets Planned API
Info callout — label + description
EBCallout(
    title: "Add title here",
    description: "This is a short helpful context message for the user."
)
    .ebIntent(.info)
    .ebLabelSize(.default)
EBCallout(
    title = "Add title here",
    description = "This is a short helpful context message for the user.",
    intent = EBCalloutIntent.Info,
    labelSize = EBCalloutLabelSize.Default
)
With trailing action (Learn more)
EBCallout(
    title: "Verify your number",
    description: "We'll send a one-time code to confirm this device."
)
    .ebIntent(.info)
    .ebTrailingAction {
        EBTextButton("Learn more") { showSheet = true }
    }
EBCallout(
    title = "Verify your number",
    description = "We'll send a one-time code to confirm this device.",
    intent = EBCalloutIntent.Info,
    trailingAction = {
        EBTextButton("Learn more", onClick = { showSheet = true })
    }
)
Warning intent (new)
EBCallout(
    description: "Transfers above ₱50,000 require ID verification."
)
    .ebIntent(.warning)
    .ebLabelSize(.none)
EBCallout(
    description = "Transfers above ₱50,000 require ID verification.",
    intent = EBCalloutIntent.Warning,
    labelSize = EBCalloutLabelSize.None
)
Accessibility
RequirementiOSAndroid
Don't rely on colour alone Pair intent with a leading icon (info / warning / error). WCAG 1.4.1. Same — both icon and color must carry intent.
Semantic grouping Wrap label + description in an accessibilityElement(children: .combine) so VoiceOver reads them as one note. Use Modifier.semantics(mergeDescendants = true).
Live-region announce If the callout appears after a user action, post a UIAccessibility.Notification.announcement with its text. Use liveRegion = LiveRegionMode.Polite when the callout mounts.
Tappable callout target Minimum 44 × 44 pt if the whole container is tappable. Minimum 48 × 48 dp same.
Dynamic type / font scaling Label and description both scale with Dynamic Type; don't hard-lock line-height to 16/20. Use sp units and respect fontScale.
Usage Guidelines

Do

Use Callout for soft, inline guidance — a flow hint, a policy reminder, a "this is what happens next" note.

Don't

Use Callout for page-level critical messages — reach for Alert when the severity warrants a dismissible banner.

Do

Pair intent colour with a leading icon. Every intent ships a default (info-circle, check-circle, warning-triangle, error-circle).

Don't

Rely on colour alone to communicate severity — fails WCAG 1.4.1 and breaks for colour-blind users.

Do

Put a single TextButton in the trailing action slot when the callout opens a sheet or links to docs.

Don't

Nest a full filled Button — it overweights the callout. If the call to action is primary, it belongs outside the callout.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Requires Rework Component name "Contextual Help" is internal jargon. Rename to Callout. Inner layers are reasonable.
C2 Variant & Property Naming Requires Rework Redundant label + label size encode one concept; type is a 2-value stub of a 4-value intent.
C3 Token Coverage Ready All bg / border / label / description bound to main/contextual-help/color/*. Spacing uses space/*. Rename namespace alongside the component rename.
C4 Native Mappability Requires Rework No leading-icon slot, no trailing-action slot, no system primitive match on either platform — custom EBCallout with intent enum required.
C5 Interaction State Coverage Requires Rework No Pressed, Focused, or Disabled states. Tappable callouts and disabled-form contexts can't be expressed.
C6 Asset & Icon Quality Requires Rework No icons shipped today — Information variant carries intent via colour alone. Add vector Icon instances per intent.
C7 Code Connect Linkability Not Mapped Blocked by rename + property schema collapse + intent expansion + slot additions.
Code Connect
Aspect Status Notes
Component name Requires Rework Rename to Callout before Code Connect — otherwise the native file EBCallout.swift won't match the Figma name Contextual Help.
Property naming Requires Rework Collapse label+label size and expand type.
Slot inference Requires Rework Add #leading-icon and #trailing-action slots.
State coverage Requires Rework Add Pressed and Disabled states.
Native component file Not Mapped Planned: EBCallout.swift / EBCallout.kt.
Variants Inventory (8 total)

4 axes: Label (yes/no) × Label Size (small / default / no) × Description (yes/no) × Type (default / information). Cartesian is constrained — of the 24 combinations, only 8 are shipped as valid variants.

LabelLabel SizeDescriptionTypeNode IDDimensions
yessmallyesdefault23:179896336 × 98
yessmallyesinformation23:179899336 × 98
yesdefaultyesdefault23:179902336 × 102
yesdefaultyesinformation23:179905336 × 102
nonoyesdefault23:179908336 × 84
nonoyesinformation23:179910336 × 84
yesdefaultnodefault23:179912336 × 39
yesdefaultnoinformation23:179915336 × 39
1.0.0 — April 2026Major
Initial Assessment · node 23:179895 (source name "Contextual Help")
Component assessed — 8 variants documented across Label × Label Size × Description × Type. Source Figma name is "Contextual Help"; this assessment recommends renaming to "Callout". Documented
Initial
Rename Contextual Help → Callout — Adopt the industry-standard name used by Atlassian, GitHub, Notion, Stripe. Rename token namespace to main/callout/* and native files to EBCallout. Open
C1 Open
Redundant label axes — Collapse label + label size into a single labelSize: none | small | default enum. Three invalid Cartesian cells removed. Open
C2 Open
Expand type to 4-value intent — Replace type=default | information with intent: info | success | warning | error. Adds token groups for success / warning / error. Open
C2 Open
Add leading-icon slot — Every intent ships a default icon (info-circle, check-circle, warning-triangle, error-circle). Closes the colour-only accessibility gap. Open
C4 Open
Add trailing action slot — Figma Slot for a single TextButton or dismiss X. Consumers instance-swap into the slot. Open
C4 Open
Add Pressed and Disabled states — Pressed for tappable callouts; Disabled to mirror parent form disabled context. Open
C5 Open
No icons shipped — Information variant signals intent via colour alone. Add DS Icon library instances per intent. Open
C6 Open
Code Connect mappings — Not registered. Blocked by rename + property collapse + intent expansion + slot additions. Open
C7 Open