Skip to content

Compose: Add DaxSnackbar to ADS#9044

Open
0nko wants to merge 5 commits into
developfrom
feature/ondrej/migrate-snackbar-to-compose
Open

Compose: Add DaxSnackbar to ADS#9044
0nko wants to merge 5 commits into
developfrom
feature/ondrej/migrate-snackbar-to-compose

Conversation

@0nko

@0nko 0nko commented Jun 29, 2026

Copy link
Copy Markdown
Member

Task/Issue URL: https://app.asana.com/1/137249556945/project/1207418217763355/task/1211670072973944?focus=true

Description

Adds the Compose DaxSnackbar to the ADS. Both overloads are thin wrappers over Material3 Snackbar with DDG design tokens (surface background, primary text, accent-blue action, 8dp corners per the component Figma):

  • DaxSnackbar(message, action?) — the visual component (message + optional trailing action). For previews, the ADS catalog, or any caller that owns its own visibility.
  • DaxSnackbar(snackbarData) — for use inside a Compose SnackbarHost (SnackbarHost(hostState) { DaxSnackbar(it) }); reads the message/action label and wires performAction(). Duration, placement and swipe-to-dismiss are owned by the host's SnackbarHostState.

Also adds the NoRawM3SnackbarUsage lint rule (errors on raw Material3 Snackbar outside the design-system modules; the legacy View Snackbar.make API is untouched) and a showcase in the ADS internal catalog.

Steps to test this PR

ADS catalog

  • Open Settings → "Android Design System Preview" → Messaging tab
  • Scroll to the Snackbar section
  • Under the "COMPOSE" label, verify two DaxSnackbar cards render — message-only, and message + "Action"
  • Confirm the above in both light and dark themes
  • Tap the Compose "Action" button
  • Verify an "Action pressed" toast appears

Note

Low Risk
New design-system UI and lint-only enforcement; no production feature flows or security-sensitive logic changed.

Overview
Introduces DaxSnackbar as the design-system snackbar for Compose: a message-only overload for static/catalog use and a SnackbarData overload for SnackbarHost, styled with DDG tokens (surface background, primary text, DaxGhostButton action).

The ADS internal catalog Snackbar section now shows the legacy View Snackbar.make demo alongside Compose DaxSnackbar examples (theme-aware via isDarkTheme). A new NoRawM3SnackbarUsage lint rule (registered in DuckDuckGoIssueRegistry) errors on raw androidx.compose.material3.Snackbar outside design-system modules, with unit tests mirroring the existing raw-M3 component detectors.

Reviewed by Cursor Bugbot for commit 66bd7c1. Bugbot is set up for automated code reviews on this repo. Configure here.

@0nko 0nko marked this pull request as ready for review June 29, 2026 13:21
@mikescamell mikescamell self-assigned this Jun 30, 2026
* Figma reference: https://www.figma.com/design/BOHDESHODUXK7wSRNBOHdu/%F0%9F%A4%96-Android-Components?node-id=6550-55049
*/
@Composable
fun DaxSnackbar(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 I think we should at least have a preview of this Composable variant 👍

Comment on lines +124 to +143
val shape: Shape
@Composable
@ReadOnlyComposable
get() = DuckDuckGoTheme.shapes.small

val containerColor: Color
@Composable
@ReadOnlyComposable
get() = DuckDuckGoTheme.colors.backgrounds.surface

val contentColor: Color
@Composable
@ReadOnlyComposable
get() = DuckDuckGoTheme.textColors.primary

val actionColor: Color
@Composable
@ReadOnlyComposable
get() = DuckDuckGoTheme.colors.brand.accentBlue
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 These properties should all be PascalCase to match Compose guidelines (yes we're being a bit inconsistent with existing Composables, I've made a task to address it)

fun DaxSnackbar(
message: String,
modifier: Modifier = Modifier,
action: DaxAction? = null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓Why did we opt to use DaxAction here? If we need something similar I think ideally it's specific to the Snackbar, otherwise if we really do need it here then DaxAction needs to be extracted from DaxMessage


@PreviewLightDark
@Composable
private fun DaxSnackbarLongMessagePreview() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓Any idea why the bottom padding for this long snackbar is particuarly small compared to the other snackbars?

* Reads the message and optional action label from [snackbarData] and delegates to the visual
* [DaxSnackbar] overload; tapping the action invokes [SnackbarData.performAction]. Trigger snackbars
* via [SnackbarHostState.showSnackbar]. A dismiss action ([SnackbarData]'s `withDismissAction`) is
* not rendered — the DDG snackbar design exposes only the message and an optional action.

@mikescamell mikescamell Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 The suppression itself is correct, and matches the View Snackbar, which never had a dismiss "X". It's worth making the consequence explicit, since it diverges from the View world. The View Snackbar is swipe-dismissable by default (DDG even opts out via NonDismissibleBehavior), whereas a Compose
SnackbarHost has no swipe-to-dismiss, so an indefinite snackbar with no action can only be dismissed in code.

Suggested change
* not rendered — the DDG snackbar design exposes only the message and an optional action.
* not rendered. The DDG snackbar design exposes only the message and an optional action. Unlike the
* View `Snackbar`, a Compose `SnackbarHost` has no swipe-to-dismiss, so a `SnackbarDuration.Indefinite`
* snackbar with no `actionLabel` can only be dismissed in code via [SnackbarHostState.currentSnackbarData].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants