diff --git a/core/api.txt b/core/api.txt
index 745d82786af..7cc6d2f0389 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -2016,9 +2016,11 @@ ion-toast,css-prop,--width,md
 ion-toast,part,button
 ion-toast,part,button cancel
 ion-toast,part,container
+ion-toast,part,content
 ion-toast,part,header
 ion-toast,part,icon
 ion-toast,part,message
+ion-toast,part,wrapper
 
 ion-toggle,shadow
 ion-toggle,prop,alignment,"center" | "start" | undefined,undefined,false,false
diff --git a/core/src/components/toast/test/custom/toast.e2e.ts b/core/src/components/toast/test/custom/toast.e2e.ts
new file mode 100644
index 00000000000..a607e3e238b
--- /dev/null
+++ b/core/src/components/toast/test/custom/toast.e2e.ts
@@ -0,0 +1,133 @@
+import { expect } from '@playwright/test';
+import { configs, test } from '@utils/test/playwright';
+
+/**
+ * This behavior does not vary across directions
+ */
+configs({ directions: ['ltr'] }).forEach(({ config, title }) => {
+  test.describe(title('toast: custom'), () => {
+    test('should be able to customize toast wrapper, container, and content using css parts', async ({ page }) => {
+      await page.setContent(
+        `
+        
+
+        
+      `,
+        config
+      );
+
+      const wrapperColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="wrapper"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).backgroundColor : null;
+      });
+
+      expect(wrapperColor).toBe('rgb(255, 0, 0)');
+
+      const containerColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="container"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).backgroundColor : null;
+      });
+
+      expect(containerColor).toBe('rgb(0, 128, 0)');
+
+      const contentColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="content"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).backgroundColor : null;
+      });
+
+      expect(contentColor).toBe('rgb(0, 0, 255)');
+    });
+
+    test('should be able to customize toast header and message using css parts', async ({ page }) => {
+      await page.setContent(
+        `
+        
+
+        
+      `,
+        config
+      );
+
+      const headerColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="header"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).color : null;
+      });
+
+      expect(headerColor).toBe('rgb(255, 0, 0)');
+
+      const messageColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="message"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).color : null;
+      });
+
+      expect(messageColor).toBe('rgb(0, 128, 0)');
+    });
+
+    test('should be able to customize toast icon, button, and button cancel using css parts', async ({ page }) => {
+      await page.setContent(
+        `
+        
+
+        
+
+        
+      `,
+        config
+      );
+
+      const iconColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="icon"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).color : null;
+      });
+
+      expect(iconColor).toBe('rgb(255, 0, 0)');
+
+      const buttonColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="button"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).color : null;
+      });
+
+      expect(buttonColor).toBe('rgb(0, 128, 0)');
+
+      const buttonCancelColor = await page.locator('ion-toast').evaluate((el: any) => {
+        const partEl = el.shadowRoot?.querySelector('[part="button cancel"]') as HTMLElement | null;
+        return partEl ? getComputedStyle(partEl).color : null;
+      });
+
+      expect(buttonCancelColor).toBe('rgb(0, 0, 255)');
+    });
+  });
+});
diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx
index 4fdcc90f42a..6f0929662af 100644
--- a/core/src/components/toast/toast.tsx
+++ b/core/src/components/toast/toast.tsx
@@ -47,12 +47,14 @@ import type {
 /**
  * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
  *
- * @part button - Any button element that is displayed inside of the toast.
- * @part button cancel - Any button element with role "cancel" that is displayed inside of the toast.
- * @part container - The element that wraps all child elements.
+ * @part wrapper - The outer wrapper for the toast overlay.
+ * @part container - Groups the icon, content, and buttons.
+ * @part content - The live region that contains the header and message.
  * @part header - The header text of the toast.
  * @part message - The body text of the toast.
  * @part icon - The icon that appears next to the toast content.
+ * @part button - Any button element that is displayed inside of the toast.
+ * @part button cancel - Any button element with role "cancel" that is displayed inside of the toast.
  */
 @Component({
   tag: 'ion-toast',
@@ -727,7 +729,7 @@ export class Toast implements ComponentInterface, OverlayInterface {
         })}
         onIonToastWillDismiss={this.dispatchCancelHandler}
       >
-        
+        
           
             {this.renderButtons(startButtons, 'start')}
 
@@ -746,7 +748,7 @@ export class Toast implements ComponentInterface, OverlayInterface {
               not interrupt the user which is why this has
               a "status" role and a "polite" presentation.
             */}
-            
+            
               {/*
                 This logic below is done to improve consistency
                 across platforms when showing and updating live regions.