Repository: govuk-one-login/mobile-android-ui
Pull request #208: feat: add new warning component
Author: login: obinns-dd
Labels: name: enhancement
description: New feature or request
Created: 2025-03-03T14:57:07Z | Merged: 2025-03-04T15:08:15Z

[Tutorial for writing good descriptions]: https://cbea.ms/git-commit/

[//]: # (Be mindful that the PR title also needs to follow conventional commit standards)

# DCMAW-11664: Warning Component

- add new warning component to design system

## Evidence of the change

See paparazzi screenshots in files changed.

## Checklist

### Before creating the pull request

- [x] Commit messages that conform to conventional commit messages.
- [x] Ran the app locally ensuring it builds.
- [x] Tests pass locally.
- [x] Pull request has a clear title with a short description about the feature or update.
- [ ] ~~Created a `draft` pull request if it's not ready for review.~~

### Before the CODEOWNERS review the pull request

- [x] Complete all Acceptance Criteria within Jira ticket.
- [x] Self-review code.
- [x] Successfully run changes on a testing device.
- [x] Complete automated Testing:
  * [ ] Unit Tests.
  * [ ] Integration Tests.
  * [ ] Instrumentation / Emulator Tests.
- [x] Review [Accessibility considerations].
- [x] Handle PR comments.

### Before merging the pull request

- [x] [Sonar cloud report] passes inspections for your PR.
- [x] Resolve all comments.

[Sonar cloud report]: https://sonarcloud.io/project/overview?id=di-mobile-android-ui
[Accessibility considerations]: https://developer.android.com/guide/topics/ui/accessibility/testing



Diff:
diff --git a/componentsv2/build.gradle.kts b/componentsv2/build.gradle.kts
index 9fa1b91b..c633a539 100644
--- a/componentsv2/build.gradle.kts
+++ b/componentsv2/build.gradle.kts
@@ -85,10 +85,13 @@ dependencies {
     androidTestImplementation(libs.androidx.test.espresso.core)
     androidTestUtil(libs.androidx.test.orchestrator)
 
+    testImplementation(libs.androidx.ui.test.android)
+    testImplementation(libs.androidx.ui.test.junit4.android)
     testImplementation(libs.arch.core)
     testImplementation(libs.hilt.android.testing)
     testImplementation(libs.junit)
     testImplementation(libs.mockito.kotlin)
+    testImplementation(libs.robolectric)
     lintChecks(libs.com.slack.compose.lint.checks)
 }
 
diff --git a/componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt b/componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
new file mode 100644
index 00000000..f231da8e
--- /dev/null
+++ b/componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
@@ -0,0 +1,78 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import uk.gov.android.ui.componentsv2.R
+import uk.gov.android.ui.theme.m3.GdsTheme
+import uk.gov.android.ui.theme.m3.Typography
+import uk.gov.android.ui.theme.spacingDouble
+import uk.gov.android.ui.theme.spacingSingleAndAHalf
+
+@Composable
+fun GdsWarning(
+    text: String,
+    modifier: Modifier = Modifier,
+) {
+    val warningText = stringResource(id = R.string.warning)
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier
+            .fillMaxWidth()
+            .padding(horizontal = spacingDouble)
+            .semantics(mergeDescendants = true) { },
+    ) {
+        Icon(
+            painter = painterResource(R.drawable.ic_error),
+            contentDescription = "$warningText\n",
+            tint = MaterialTheme.colorScheme.onBackground,
+        )
+        Spacer(Modifier.size(spacingSingleAndAHalf))
+        Text(
+            text,
+            color = MaterialTheme.colorScheme.onBackground,
+            style = Typography.bodyMedium,
+            fontWeight = FontWeight.Bold,
+        )
+    }
+}
+
+internal class WarningPreviewProvider : PreviewParameterProvider<String> {
+    override val values: Sequence<String> = sequenceOf(
+        "text",
+        listOf(
+            "lorem ipsum dolor sit amet consectetur.",
+            "Purus aliquam mattis vitae enim mauris.",
+            "lorem ipsum dolor sit amet consectetur.",
+        ).joinToString(" "),
+
+    )
+}
+
+@PreviewLightDark
+@Composable
+internal fun WarningPreview(
+    @PreviewParameter(WarningPreviewProvider::class)
+    text: String,
+) {
+    GdsTheme {
+        GdsWarning(
+            text = text,
+        )
+    }
+}
diff --git a/componentsv2/src/main/res/drawable/ic_error.xml b/componentsv2/src/main/res/drawable/ic_error.xml
new file mode 100644
index 00000000..fa63ee3a
--- /dev/null
+++ b/componentsv2/src/main/res/drawable/ic_error.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="30dp"
+    android:height="30dp"
+    android:viewportWidth="30"
+    android:viewportHeight="30">
+  <group>
+    <clip-path
+        android:pathData="M0,0h30v30h-30z"/>
+    <path
+        android:pathData="M15,22.5C15.425,22.5 15.781,22.356 16.069,22.069C16.356,21.781 16.5,21.425 16.5,21C16.5,20.575 16.356,20.219 16.069,19.931C15.781,19.644 15.425,19.5 15,19.5C14.575,19.5 14.219,19.644 13.931,19.931C13.644,20.219 13.5,20.575 13.5,21C13.5,21.425 13.644,21.781 13.931,22.069C14.219,22.356 14.575,22.5 15,22.5ZM15,16.5C15.425,16.5 15.781,16.356 16.069,16.069C16.356,15.781 16.5,15.425 16.5,15V9C16.5,8.575 16.356,8.219 16.069,7.931C15.781,7.644 15.425,7.5 15,7.5C14.575,7.5 14.219,7.644 13.931,7.931C13.644,8.219 13.5,8.575 13.5,9V15C13.5,15.425 13.644,15.781 13.931,16.069C14.219,16.356 14.575,16.5 15,16.5ZM15,30C12.925,30 10.975,29.606 9.15,28.819C7.325,28.031 5.738,26.962 4.387,25.612C3.037,24.263 1.969,22.675 1.181,20.85C0.394,19.025 0,17.075 0,15C0,12.925 0.394,10.975 1.181,9.15C1.969,7.325 3.037,5.738 4.387,4.387C5.738,3.037 7.325,1.969 9.15,1.181C10.975,0.394 12.925,0 15,0C17.075,0 19.025,0.394 20.85,1.181C22.675,1.969 24.263,3.037 25.612,4.387C26.962,5.738 28.031,7.325 28.819,9.15C29.606,10.975 30,12.925 30,15C30,17.075 29.606,19.025 28.819,20.85C28.031,22.675 26.962,24.263 25.612,25.612C24.263,26.962 22.675,28.031 20.85,28.819C19.025,29.606 17.075,30 15,30Z"
+        android:fillColor="#000000"/>
+  </group>
+</vector>
diff --git a/componentsv2/src/main/res/values-cy/strings.xml b/componentsv2/src/main/res/values-cy/strings.xml
index f7129f1b..17dd17c2 100644
--- a/componentsv2/src/main/res/values-cy/strings.xml
+++ b/componentsv2/src/main/res/values-cy/strings.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-
     <!-- BulletedList -->
     <string name="bullet">bwled %s</string>
     <string name="heading">penawd</string>
@@ -11,4 +10,7 @@
         <item quantity="few">rhestr bwledi %d eitem. bwled %s</item>
         <item quantity="many">rhestr bwledi %d eitem. bwled %s</item>
     </plurals>
+
+    <!-- Warning -->
+    <string name="warning">rhybudd</string>
 </resources>
\ No newline at end of file
diff --git a/componentsv2/src/main/res/values/strings.xml b/componentsv2/src/main/res/values/strings.xml
index 0de471ed..6688aa81 100644
--- a/componentsv2/src/main/res/values/strings.xml
+++ b/componentsv2/src/main/res/values/strings.xml
@@ -30,4 +30,7 @@
         <item quantity="one">bulleted list %d item. bullet %s</item>
         <item quantity="other">bulleted list %d items. bullet %s</item>
     </plurals>
+
+    <!-- Warning -->
+    <string name="warning" translatable="true">warning</string>
 </resources>
\ No newline at end of file
diff --git a/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningScreenshotTest.kt b/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningScreenshotTest.kt
new file mode 100644
index 00000000..6a546bcc
--- /dev/null
+++ b/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningScreenshotTest.kt
@@ -0,0 +1,32 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.runtime.Composable
+import com.android.resources.NightMode
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import uk.gov.android.ui.componentsv2.BaseScreenshotTest
+
+@RunWith(Parameterized::class)
+internal class GdsWarningScreenshotTest(
+    private val parameters: Pair<String, NightMode>,
+) : BaseScreenshotTest(parameters.second) {
+
+    override val generateComposeLayout: @Composable () -> Unit = {
+        val parameters = parameters.first
+        GdsWarning(
+            text = parameters,
+        )
+    }
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{index}GdsIconV2")
+        fun values(): List<Pair<String, NightMode>> {
+            val result: MutableList<Pair<String, NightMode>> = mutableListOf()
+
+            WarningPreviewProvider().values.forEach(applyNightMode(result))
+
+            return result
+        }
+    }
+}
diff --git a/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningTest.kt b/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningTest.kt
new file mode 100644
index 00000000..1f8d2784
--- /dev/null
+++ b/componentsv2/src/test/java/uk/gov/android/ui/componentsv2/warning/GdsWarningTest.kt
@@ -0,0 +1,55 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.activity.ComponentActivity
+import androidx.compose.ui.test.assertContentDescriptionEquals
+import androidx.compose.ui.test.assertTextContains
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onChildren
+import androidx.compose.ui.test.onFirst
+import androidx.compose.ui.test.onLast
+import androidx.compose.ui.test.onRoot
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class GdsWarningTest {
+    private val text = "Lorem ipsum dolor sit amet."
+
+    @Rule
+    @JvmField
+    val composeTestRule = createAndroidComposeRule<ComponentActivity>()
+
+    @Before
+    fun setup() {
+        composeTestRule.setContent {
+            GdsWarning(text)
+        }
+    }
+
+    @Test
+    fun test() {
+        val warningNode = composeTestRule
+            .onRoot(true)
+            .onChild()
+
+        assertTrue(
+            warningNode
+                .fetchSemanticsNode()
+                .config
+                .isMergingSemanticsOfDescendants,
+        )
+        warningNode
+            .onChildren()
+            .onFirst()
+            .assertContentDescriptionEquals("warning\n")
+        warningNode
+            .onChildren()
+            .onLast()
+            .assertTextContains(text)
+    }
+}
diff --git a/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[0GdsIconV2].png b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[0GdsIconV2].png
new file mode 100644
index 00000000..ac8886d7
Binary files /dev/null and b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[0GdsIconV2].png differ
diff --git a/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[1GdsIconV2].png b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[1GdsIconV2].png
new file mode 100644
index 00000000..45dbcd4e
Binary files /dev/null and b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[1GdsIconV2].png differ
diff --git a/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png
new file mode 100644
index 00000000..77ddd8ca
Binary files /dev/null and b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png differ
diff --git a/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[3GdsIconV2].png b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[3GdsIconV2].png
new file mode 100644
index 00000000..3f702240
Binary files /dev/null and b/componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[3GdsIconV2].png differ
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index baa324aa..6c74bd47 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -15,13 +15,15 @@ espresso = "3.6.1" # https://developer.android.com/jetpack/androidx/releases/tes
 junit = "4.13.2" # https://github.com/junit-team/junit4/releases
 junit-bom = "5.11.4"
 kotlin = "2.1.10" # https://kotlinlang.org/docs/releases.html#release-details
+kotlinx-collections-immutable="0.3.8"
+ktlint-cli = "0.49.1"
 ktlint-gradle = "12.2.0" # https://github.com/JLLeitschuh/ktlint-gradle/releases
 material = "1.12.0" # https://github.com/mockito/mockito-kotlin/releases
 mockito-kotlin = "5.4.0" # https://github.com/mockito/mockito-kotlin/releases
 paparazzi = "1.3.5"
+robolectric = "4.12"
 sonarqube-gradle = "6.0.1.5171" # https://github.com/SonarSource/sonar-scanner-gradle/releases
-ktlint-cli = "0.49.1"
-kotlinx-collections-immutable="0.3.8"
+ui-test-android = "1.7.8"
 
 [libraries]
 android-build-tool = { group = "com.android.tools.build", name = "gradle", version.ref = "android-gradle" }
@@ -42,6 +44,9 @@ androidx-compose-ui-testmanifest = { group = "androidx.compose.ui", name = "ui-t
 androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
 androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
 androidx-test-orchestrator = { module = "androidx.test:orchestrator", version.ref = "androidx-test-orchestrator" }
+androidx-ui-test-android = { group = "androidx.compose.ui", name = "ui-test-android", version.ref = "ui-test-android" }
+androidx-ui-test-junit4-android = { group = "androidx.compose.ui", name = "ui-test-junit4-android", version.ref = "ui-test-android" }
+robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
 
 appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
 arch-core = { group = "androidx.arch.core", name = "core-testing", version.ref = "archcore-testing" }
diff --git a/theme/src/main/java/uk/gov/android/ui/theme/Dimensions.kt b/theme/src/main/java/uk/gov/android/ui/theme/Dimensions.kt
index a3ea44dd..2c5a4498 100644
--- a/theme/src/main/java/uk/gov/android/ui/theme/Dimensions.kt
+++ b/theme/src/main/java/uk/gov/android/ui/theme/Dimensions.kt
@@ -10,6 +10,7 @@ val bulletSize = 8.dp
 val scannedImageThumbnailWidth = 100.dp
 val scannedImageThumbnailHeight = 126.dp
 val spacingSingle = 8.dp
+val spacingSingleAndAHalf = 12.dp
 val spacingDouble = 16.dp
 val spacingTriple = 24.dp
 val textSizeBody = 17.sp


Reviews:
user: login: jonnyandrew
body: Looks good, just a few minor comments!
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T10:09:12Z
user: login: obinns-dd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T12:01:11Z
user: login: obinns-dd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T12:01:26Z
user: login: obinns-dd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:23:13Z
user: login: BiancaMihaila
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:31:12Z
user: login: BiancaMihaila
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:31:30Z
user: login: jonnyandrew
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:52:44Z
user: login: jonnyandrew
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:58:57Z
user: login: jonnyandrew
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:59:54Z
user: login: jonnyandrew
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T15:08:21Z

Review comments:
diff_hunk: @@ -62,6 +62,8 @@ android {
 }
 
 dependencies {
+    implementation(libs.androidx.ui.test.android)
+    implementation(libs.androidx.ui.test.junit4.android)
path: componentsv2/build.gradle.kts
user: login: jonnyandrew
body: Should these test dependencies have been added to the to the `implementation` config?
created_at: 2025-03-04T09:56:49Z
author_association: CONTRIBUTOR
path: componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png
user: login: jonnyandrew
body: I think we changed components so that the horizontal padding that's always required gets included with it (see #204) - maybe the same is needed here?
created_at: 2025-03-04T10:01:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import uk.gov.android.ui.componentsv2.R
+import uk.gov.android.ui.theme.m3.GdsTheme
+
+@Composable
+fun GdsWarning(
+    text: String,
+    modifier: Modifier = Modifier,
+) {
+    val warningText = stringResource(id = R.string.warning)
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier
+            .fillMaxWidth()
+            .semantics(mergeDescendants = true) { },
+    ) {
+        Icon(
+            painter = painterResource(R.drawable.ic_error),
+            contentDescription = "$warningText\n",
+            tint = MaterialTheme.colorScheme.onBackground,
+        )
+        Spacer(Modifier.size(12.dp))
+        Text(
+            text,
+            color = MaterialTheme.colorScheme.onBackground,
path: componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
user: login: jonnyandrew
body: (not blocking, question)

I thought the colour of these components should be derived automatically based on the background colour, so there shouldn't be any need to specify. As internally they use `LocalTextStyle.current` and falls back to `LocalContentColor.current`.

I understood these should be based on the the theme - 

> `LocalContentColor.current` typically represents the 'on' color for a color in ColorScheme. For example, if the background color is `ColorScheme.surface,` this color is typically set to `ColorScheme.onSurface`.

So a question really: is this something that isn't working and that we need to fix in the theme?
created_at: 2025-03-04T10:08:51Z
author_association: CONTRIBUTOR
path: componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png
user: login: obinns-dd
body: Sure that's done - probably worth having a discussion around this, because if there's a screen that's already got padding on it, we don't want double padding, but I'll follow the existing convention for now!
created_at: 2025-03-04T12:01:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +62,8 @@ android {
 }
 
 dependencies {
+    implementation(libs.androidx.ui.test.android)
+    implementation(libs.androidx.ui.test.junit4.android)
path: componentsv2/build.gradle.kts
user: login: obinns-dd
body: Nope, good catch- I've moved them to `testImplementation`
created_at: 2025-03-04T12:01:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import uk.gov.android.ui.componentsv2.R
+import uk.gov.android.ui.theme.m3.GdsTheme
+
+@Composable
+fun GdsWarning(
+    text: String,
+    modifier: Modifier = Modifier,
+) {
+    val warningText = stringResource(id = R.string.warning)
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier
+            .fillMaxWidth()
+            .semantics(mergeDescendants = true) { },
+    ) {
+        Icon(
+            painter = painterResource(R.drawable.ic_error),
+            contentDescription = "$warningText\n",
+            tint = MaterialTheme.colorScheme.onBackground,
+        )
+        Spacer(Modifier.size(12.dp))
+        Text(
+            text,
+            color = MaterialTheme.colorScheme.onBackground,
path: componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
user: login: obinns-dd
body: Yes, the colours don't work in dark mode without specifying them; I've copied the examples used in other components so I'd suggest we pick this up separately if we think it's an issue.
created_at: 2025-03-04T14:23:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,78 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import uk.gov.android.ui.componentsv2.R
+import uk.gov.android.ui.theme.m3.GdsTheme
+import uk.gov.android.ui.theme.m3.Typography
+import uk.gov.android.ui.theme.spacingDouble
+
+@Composable
+fun GdsWarning(
+    text: String,
+    modifier: Modifier = Modifier,
+) {
+    val warningText = stringResource(id = R.string.warning)
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier
+            .fillMaxWidth()
+            .padding(horizontal = spacingDouble)
+            .semantics(mergeDescendants = true) { },
+    ) {
+        Icon(
+            painter = painterResource(R.drawable.ic_error),
+            contentDescription = "$warningText\n",
+            tint = MaterialTheme.colorScheme.onBackground,
+        )
+        Spacer(Modifier.size(12.dp))
path: componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
user: login: BiancaMihaila
body: More of a nitpick - but could we maybe save the `12.dp` as a var in dimensions to re-use, not to be done now but I think that's how we've been doing it before, unless there's a reason we shouldn't be doing it
created_at: 2025-03-04T14:31:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+package uk.gov.android.ui.componentsv2.warning
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import uk.gov.android.ui.componentsv2.R
+import uk.gov.android.ui.theme.m3.GdsTheme
+
+@Composable
+fun GdsWarning(
+    text: String,
+    modifier: Modifier = Modifier,
+) {
+    val warningText = stringResource(id = R.string.warning)
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier
+            .fillMaxWidth()
+            .semantics(mergeDescendants = true) { },
+    ) {
+        Icon(
+            painter = painterResource(R.drawable.ic_error),
+            contentDescription = "$warningText\n",
+            tint = MaterialTheme.colorScheme.onBackground,
+        )
+        Spacer(Modifier.size(12.dp))
+        Text(
+            text,
+            color = MaterialTheme.colorScheme.onBackground,
path: componentsv2/src/main/java/uk/gov/android/ui/componentsv2/warning/GdsWarning.kt
user: login: jonnyandrew
body: Yeah that makes sense!

Maybe it's worth adding a note to this similar ticket so it doesn't get forgotten about? https://govukverify.atlassian.net/browse/DCMAW-11635
created_at: 2025-03-04T14:52:43Z
author_association: CONTRIBUTOR
path: componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png
user: login: jonnyandrew
body: We did have a quick discussion about it and the rationale was that screens don't have any global padding because there are elements that go edge to edge (images being the example).

So we decided to include the padding in the components themselves.

But it's not the only way we could have done it - and definitely worth revisiting if you feel it's going to cause problems?
created_at: 2025-03-04T14:58:56Z
author_association: CONTRIBUTOR
path: componentsv2/src/test/snapshots/images/uk.gov.android.ui.componentsv2.warning_GdsWarningScreenshotTest_testScreenshot[2GdsIconV2].png
user: login: jonnyandrew
body: (I am also not convinced we couldn't come up with a better solution)
created_at: 2025-03-04T14:59:54Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-04T15:05:27Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=mobile-android-ui&pullRequest=208) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=mobile-android-ui&pullRequest=208&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=mobile-android-ui&pullRequest=208&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=mobile-android-ui&pullRequest=208&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [46.9% Coverage on New Code](https://sonarcloud.io/component_measures?id=mobile-android-ui&pullRequest=208&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=mobile-android-ui&pullRequest=208&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=mobile-android-ui&pullRequest=208)


author_association: NONE