+
+
+
+
+
+ );
+ },
+);
+
+Toast.displayName = 'Toast';
diff --git a/packages/ui/src/components/Toast/ToastRegion.tsx b/packages/ui/src/components/Toast/ToastRegion.tsx
new file mode 100644
index 0000000000..b5a004e12a
--- /dev/null
+++ b/packages/ui/src/components/Toast/ToastRegion.tsx
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { forwardRef, Ref, useEffect, useState } from 'react';
+import { UNSTABLE_ToastRegion as RAToastRegion } from 'react-aria-components';
+import type { ToastRegionProps } from './types';
+import { useDefinition } from '../../hooks/useDefinition';
+import { ToastRegionDefinition } from './definition';
+import { Toast } from './Toast';
+
+/**
+ * A ToastRegion displays one or more toast notifications.
+ *
+ * @remarks
+ * The ToastRegion component should typically be placed once at the root of your application.
+ * It manages the display and positioning of all toast notifications added to its queue.
+ * Toast regions are ARIA landmark regions that can be navigated using F6 (forward) and
+ * Shift+F6 (backward) for keyboard accessibility.
+ *
+ * This component uses React Aria's unstable Toast API which is currently in alpha.
+ *
+ * @example
+ * Basic setup in app root:
+ * ```tsx
+ * import { ToastRegion, queue } from '@backstage/ui';
+ *
+ * function App() {
+ * return (
+ * <>
+ *
+ *
+ * >
+ * );
+ * }
+ * ```
+ *
+ * @example
+ * Custom positioning:
+ * ```tsx
+ *
+ * ```
+ *
+ * @public
+ */
+export const ToastRegion = forwardRef(
+ (props: ToastRegionProps, ref: Ref) => {
+ const { ownProps, restProps, dataAttributes } = useDefinition(
+ ToastRegionDefinition,
+ props,
+ );
+ const { classes, queue, className } = ownProps;
+
+ // Track visible toast keys to determine index
+ const [visibleToasts, setVisibleToasts] = useState([]);
+
+ useEffect(() => {
+ const updateToasts = () => {
+ setVisibleToasts(queue.visibleToasts.map(t => t.key));
+ };
+
+ // Subscribe to queue changes
+ const unsubscribe = queue.subscribe(updateToasts);
+ updateToasts(); // Initial update
+
+ return unsubscribe;
+ }, [queue]);
+
+ return (
+
+ {({ toast }) => {
+ const index = visibleToasts.indexOf(toast.key);
+ return = 0 ? index : 0} />;
+ }}
+
+ );
+ },
+);
+
+ToastRegion.displayName = 'ToastRegion';
diff --git a/packages/ui/src/components/Toast/definition.ts b/packages/ui/src/components/Toast/definition.ts
new file mode 100644
index 0000000000..b542d6aa82
--- /dev/null
+++ b/packages/ui/src/components/Toast/definition.ts
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { defineComponent } from '../../hooks/useDefinition';
+import type { ToastOwnProps, ToastRegionOwnProps } from './types';
+import styles from './Toast.module.css';
+
+/**
+ * Component definition for Toast
+ * @public
+ */
+export const ToastDefinition = defineComponent()({
+ styles,
+ classNames: {
+ root: 'bui-Toast',
+ content: 'bui-ToastContent',
+ title: 'bui-ToastTitle',
+ description: 'bui-ToastDescription',
+ icon: 'bui-ToastIcon',
+ closeButton: 'bui-ToastCloseButton',
+ },
+ surface: 'container',
+ propDefs: {
+ toast: {},
+ index: {},
+ status: { dataAttribute: true },
+ icon: {},
+ },
+});
+
+/**
+ * Component definition for ToastRegion
+ * @public
+ */
+export const ToastRegionDefinition = defineComponent()({
+ styles,
+ classNames: {
+ region: 'bui-ToastRegion',
+ },
+ propDefs: {
+ queue: {},
+ position: { dataAttribute: true, default: 'bottom' },
+ placement: { dataAttribute: true, default: 'end' },
+ className: {},
+ },
+});
diff --git a/packages/ui/src/components/Toast/index.ts b/packages/ui/src/components/Toast/index.ts
new file mode 100644
index 0000000000..46d5f6c7e8
--- /dev/null
+++ b/packages/ui/src/components/Toast/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { Toast } from './Toast';
+export { ToastRegion } from './ToastRegion';
+export * from './types';
+export { ToastDefinition, ToastRegionDefinition } from './definition';
+export { toastQueue } from './queue';
diff --git a/packages/ui/src/components/Toast/queue.ts b/packages/ui/src/components/Toast/queue.ts
new file mode 100644
index 0000000000..bb5e57d980
--- /dev/null
+++ b/packages/ui/src/components/Toast/queue.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { UNSTABLE_ToastQueue as RAToastQueue } from 'react-aria-components';
+import type { ToastContent } from './types';
+
+/**
+ * Global toast queue for displaying toast notifications throughout the application.
+ *
+ * @remarks
+ * This uses React Aria's unstable Toast API which is currently in alpha.
+ * The API may change in future versions.
+ *
+ * @example
+ * ```tsx
+ * import { toastQueue } from '@backstage/ui';
+ *
+ * // Show a toast
+ * toastQueue.add({ title: 'Success!', status: 'success' });
+ *
+ * // Show with auto-dismiss
+ * toastQueue.add({ title: 'Saved' }, { timeout: 5000 });
+ *
+ * // Programmatic dismiss
+ * const key = toastQueue.add({ title: 'Processing...' });
+ * // Later...
+ * toastQueue.close(key);
+ * ```
+ *
+ * @public
+ */
+export const toastQueue = new RAToastQueue({});
diff --git a/packages/ui/src/components/Toast/types.ts b/packages/ui/src/components/Toast/types.ts
new file mode 100644
index 0000000000..5bdccc5edd
--- /dev/null
+++ b/packages/ui/src/components/Toast/types.ts
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { ReactElement, ReactNode } from 'react';
+import type { UNSTABLE_ToastQueue as RAToastQueue } from 'react-aria-components';
+import type { Responsive } from '../../types';
+
+/**
+ * Content for a toast notification
+ * @public
+ */
+export interface ToastContent {
+ /** Title of the toast (required) */
+ title: ReactNode;
+ /** Optional description text */
+ description?: ReactNode;
+ /** Status variant of the toast */
+ status?: 'info' | 'success' | 'warning' | 'danger';
+ /** Whether to show an icon */
+ icon?: boolean | ReactElement;
+}
+
+/**
+ * Own props for the Toast component
+ * @public
+ */
+export type ToastOwnProps = {
+ /** Toast object from the queue */
+ toast: {
+ key: string;
+ content: ToastContent;
+ };
+ /** Index of the toast in the stack (0 = frontmost) */
+ index?: number;
+ /** Override status from content */
+ status?: Responsive<'info' | 'success' | 'warning' | 'danger'>;
+ /** Override icon from content */
+ icon?: boolean | ReactElement;
+};
+
+/**
+ * Properties for {@link Toast}
+ * @public
+ */
+export interface ToastProps extends ToastOwnProps {}
+
+/**
+ * Own props for the ToastRegion component
+ * @public
+ */
+export type ToastRegionOwnProps = {
+ /** Toast queue instance */
+ queue: RAToastQueue;
+ /** Position of the toast region (top or bottom) */
+ position?: Responsive<'top' | 'bottom'>;
+ /** Horizontal placement of toasts */
+ placement?: Responsive<'start' | 'center' | 'end'>;
+ /** Custom class name */
+ className?: string;
+};
+
+/**
+ * Properties for {@link ToastRegion}
+ * @public
+ */
+export interface ToastRegionProps extends ToastRegionOwnProps {}
diff --git a/packages/ui/src/definitions.ts b/packages/ui/src/definitions.ts
index 59003e8070..dc9b5ffddd 100644
--- a/packages/ui/src/definitions.ts
+++ b/packages/ui/src/definitions.ts
@@ -53,6 +53,10 @@ export { SearchFieldDefinition } from './components/SearchField/definition';
export { SelectDefinition } from './components/Select/definition';
export { SkeletonDefinition } from './components/Skeleton/definition';
export { SwitchDefinition } from './components/Switch/definition';
+export {
+ ToastDefinition,
+ ToastRegionDefinition,
+} from './components/Toast/definition';
export { ToggleButtonDefinition } from './components/ToggleButton/definition';
export { ToggleButtonGroupDefinition } from './components/ToggleButtonGroup/definition';
export { TableDefinition } from './components/Table/definition';
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index c70aa9d325..6dc9d5f292 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -56,6 +56,7 @@ export * from './components/Link';
export * from './components/Select';
export * from './components/Skeleton';
export * from './components/Switch';
+export * from './components/Toast';
export * from './components/ToggleButton';
export * from './components/ToggleButtonGroup';
export * from './components/VisuallyHidden';