-
-
- );
- },
-);
-
-Toast.displayName = 'Toast';
diff --git a/packages/ui/src/components/Toast/ToastContainer.tsx b/packages/ui/src/components/Toast/ToastContainer.tsx
deleted file mode 100644
index 69e5e4ac08..0000000000
--- a/packages/ui/src/components/Toast/ToastContainer.tsx
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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, useState, useRef, useCallback, useMemo } from 'react';
-import { useToastRegion } from '@react-aria/toast';
-import { useToastQueue } from 'react-stately';
-import { AnimatePresence } from 'motion/react';
-import type { ToastContainerProps } from './types';
-import { useDefinition } from '../../hooks/useDefinition';
-import { useInvertedThemeMode } from '../../hooks/useInvertedThemeMode';
-import { ToastContainerDefinition } from './definition';
-import { Toast } from './Toast';
-
-/**
- * A ToastContainer displays one or more toast notifications in the bottom-right corner.
- *
- * @remarks
- * The ToastContainer component should typically be placed once at the root of your application.
- * It manages the display and stacking of all toast notifications added to its queue.
- * Toasts appear in the bottom-right corner with deep stacking when multiple are visible.
- * Toast containers are ARIA landmark regions that can be navigated using F6 (forward) and
- * Shift+F6 (backward) for keyboard accessibility.
- *
- * @example
- * Basic setup in app root:
- * ```tsx
- * import { ToastContainer, toastQueue } from '@backstage/ui';
- *
- * function App() {
- * return (
- * <>
- *
- *
- * >
- * );
- * }
- * ```
- *
- * @public
- */
-export const ToastContainer = forwardRef(
- (props: ToastContainerProps, ref: Ref) => {
- const { ownProps, restProps, dataAttributes } = useDefinition(
- ToastContainerDefinition,
- props,
- );
- const { classes, queue, className } = ownProps;
-
- // Subscribe to the toast queue state
- const state = useToastQueue(queue);
-
- // Use internal ref if none provided
- const internalRef = useRef(null);
- const containerRef =
- (ref as React.RefObject) || internalRef;
-
- // Get ARIA props for the toast region
- const { regionProps } = useToastRegion({}, state, containerRef);
-
- // Track hover state for expanding/collapsing the stack
- const [isHovered, setIsHovered] = useState(false);
-
- // Lock expanded state after close to prevent stack collapse during exit animation
- const [isHoverLocked, setIsHoverLocked] = useState(false);
- const unlockTimerRef = useRef | null>(null);
-
- // Toasts are expanded when hovered, focused, or locked
- const isExpanded = isHovered || isHoverLocked;
-
- // Track heights of all toasts by their key
- const [toastHeights, setToastHeights] = useState>(
- {},
- );
-
- // Callback for toasts to report their height
- const handleHeightChange = useCallback((key: string, height: number) => {
- setToastHeights(prev => {
- if (prev[key] === height) return prev;
- return { ...prev, [key]: height };
- });
- }, []);
-
- // Calculate expanded Y positions and get front toast height
- const { expandedYPositions, frontToastHeight } = useMemo(() => {
- const gap = 8;
- const positions: Record = {};
- let frontHeight = 60; // Default fallback
-
- // visibleToasts[0] is the front toast (newest)
- const toasts = state.visibleToasts;
-
- if (toasts.length > 0 && toastHeights[toasts[0].key]) {
- frontHeight = toastHeights[toasts[0].key];
- }
-
- // Calculate cumulative Y position for each toast when expanded
- // Position is negative Y (moving up from bottom)
- let cumulativeY = 0;
- for (let i = 0; i < toasts.length; i++) {
- positions[toasts[i].key] = -cumulativeY;
- const height = toastHeights[toasts[i].key] || 60;
- cumulativeY += height + gap;
- }
-
- return { expandedYPositions: positions, frontToastHeight: frontHeight };
- }, [state.visibleToasts, toastHeights]);
-
- // Get inverted theme mode for toasts (light when app is dark, dark when app is light)
- const invertedThemeMode = useInvertedThemeMode();
-
- const handleClose = () => {
- // Lock the expanded state while toast is being removed
- setIsHoverLocked(true);
-
- // Clear any pending unlock
- if (unlockTimerRef.current) {
- clearTimeout(unlockTimerRef.current);
- }
-
- // Unlock after a short delay to allow exit animation to complete
- unlockTimerRef.current = setTimeout(() => {
- setIsHoverLocked(false);
- }, 500);
- };
-
- return (
-
- );
- },
-);
-
-ToastContainer.displayName = 'ToastContainer';
diff --git a/packages/ui/src/components/Toast/ToastQueue.ts b/packages/ui/src/components/Toast/ToastQueue.ts
deleted file mode 100644
index 64f4602950..0000000000
--- a/packages/ui/src/components/Toast/ToastQueue.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 { ToastQueue } from 'react-stately';
-import type { ToastContent } from './types';
-
-/**
- * Global toast queue for displaying toast notifications throughout the application.
- *
- * @remarks
- * This uses React Stately's ToastQueue for state management with motion/react
- * for smooth enter/exit animations.
- *
- * @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 ToastQueue({
- maxVisibleToasts: 4,
-});
diff --git a/packages/ui/src/components/Toast/definition.ts b/packages/ui/src/components/Toast/definition.ts
deleted file mode 100644
index 8e24583bdc..0000000000
--- a/packages/ui/src/components/Toast/definition.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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, ToastContainerOwnProps } from './types';
-import styles from './Toast.module.css';
-
-/**
- * Component definition for Toast
- * @internal
- */
-export const ToastDefinition = defineComponent()({
- styles,
- classNames: {
- root: 'bui-Toast',
- wrapper: 'bui-ToastWrapper',
- content: 'bui-ToastContent',
- title: 'bui-ToastTitle',
- description: 'bui-ToastDescription',
- links: 'bui-ToastLinks',
- icon: 'bui-ToastIcon',
- closeButton: 'bui-ToastCloseButton',
- },
- surface: 'container',
- propDefs: {
- toast: {},
- state: {},
- index: {},
- isExpanded: {},
- onClose: {},
- status: { dataAttribute: true },
- icon: {},
- surface: {},
- className: {},
- style: {},
- expandedY: {},
- collapsedHeight: {},
- naturalHeight: {},
- onHeightChange: {},
- },
-});
-
-/**
- * Component definition for ToastContainer
- * @public
- */
-export const ToastContainerDefinition =
- defineComponent()({
- styles,
- classNames: {
- container: 'bui-ToastContainer',
- },
- propDefs: {
- queue: {},
- className: {},
- },
- });
diff --git a/packages/ui/src/components/Toast/index.ts b/packages/ui/src/components/Toast/index.ts
deleted file mode 100644
index 7d3fc915a6..0000000000
--- a/packages/ui/src/components/Toast/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 { ToastContainer } from './ToastContainer';
-export { ToastContainerDefinition } from './definition';
-export { toastQueue } from './ToastQueue';
-export type {
- ToastLink,
- ToastContent,
- ToastContainerOwnProps,
- ToastContainerProps,
-} from './types';
diff --git a/packages/ui/src/components/Toast/types.ts b/packages/ui/src/components/Toast/types.ts
deleted file mode 100644
index c2a206c907..0000000000
--- a/packages/ui/src/components/Toast/types.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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 { ToastQueue, ToastState, QueuedToast } from 'react-stately';
-import type { Responsive, ContainerSurfaceProps } from '../../types';
-
-/**
- * Link item for toast notifications
- * @public
- */
-export interface ToastLink {
- /** Display text for the link */
- label: string;
- /** URL the link points to */
- href: string;
-}
-
-/**
- * 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;
- /** Optional array of links to display */
- links?: ToastLink[];
-}
-
-/**
- * Own props for the Toast component
- * @internal
- */
-export type ToastOwnProps = ContainerSurfaceProps & {
- /** Toast object from the queue */
- toast: QueuedToast;
- /** Toast state from useToastQueue */
- state: ToastState;
- /** Index of the toast in the visible toasts array */
- index?: number;
- /** Whether the toast stack is expanded (hovered/focused) */
- isExpanded?: boolean;
- /** Callback when toast is closed */
- onClose?: () => void;
- /** Override status from content */
- status?: Responsive<'info' | 'success' | 'warning' | 'danger'>;
- /** Override icon from content */
- icon?: boolean | ReactElement;
- /** Pre-calculated Y position when expanded (based on heights of toasts below) */
- expandedY?: number;
- /** Height to use when collapsed (front toast's height, for uniform stacking) */
- collapsedHeight?: number;
- /** This toast's natural height (for smooth animation) */
- naturalHeight?: number;
- /** Callback to report this toast's natural height */
- onHeightChange?: (key: string, height: number) => void;
-};
-
-/**
- * Properties for {@link Toast}
- * @internal
- */
-export interface ToastProps extends ToastOwnProps {}
-
-/**
- * Own props for the ToastContainer component
- * @public
- */
-export type ToastContainerOwnProps = {
- /** Toast queue instance */
- queue: ToastQueue;
- /** Custom class name */
- className?: string;
-};
-
-/**
- * Properties for {@link ToastContainer}
- * @public
- */
-export interface ToastContainerProps extends ToastContainerOwnProps {}
diff --git a/packages/ui/src/definitions.ts b/packages/ui/src/definitions.ts
index 2219530747..59003e8070 100644
--- a/packages/ui/src/definitions.ts
+++ b/packages/ui/src/definitions.ts
@@ -53,11 +53,6 @@ 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,
- ToastContainerDefinition,
- ToastContainerDefinition as 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/hooks/index.ts b/packages/ui/src/hooks/index.ts
index b23ed84387..b231a4ff93 100644
--- a/packages/ui/src/hooks/index.ts
+++ b/packages/ui/src/hooks/index.ts
@@ -15,4 +15,3 @@
*/
export * from './useDefinition';
-export * from './useInvertedThemeMode';
diff --git a/packages/ui/src/hooks/useInvertedThemeMode.ts b/packages/ui/src/hooks/useInvertedThemeMode.ts
deleted file mode 100644
index d93abf2863..0000000000
--- a/packages/ui/src/hooks/useInvertedThemeMode.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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 { useState, useEffect } from 'react';
-
-type ThemeMode = 'light' | 'dark';
-
-/**
- * Detects the current theme mode from the DOM and returns the inverted value.
- * Checks both document.documentElement and document.body for the data-theme-mode attribute.
- *
- * @returns The inverted theme mode ('light' when app is dark, 'dark' when app is light)
- */
-export function useInvertedThemeMode(): ThemeMode {
- const [invertedThemeMode, setInvertedThemeMode] = useState('dark');
-
- useEffect(() => {
- const detectTheme = (): ThemeMode => {
- // Check both html and body elements for the theme attribute
- const htmlTheme =
- document.documentElement.getAttribute('data-theme-mode');
- const bodyTheme = document.body.getAttribute('data-theme-mode');
-
- // Prefer body (used by UnifiedThemeProvider) over html
- const currentTheme = bodyTheme || htmlTheme;
-
- // If current theme is dark, return light (inverted), otherwise return dark
- return currentTheme === 'dark' ? 'light' : 'dark';
- };
-
- // Initial detection
- setInvertedThemeMode(detectTheme());
-
- // Watch for theme changes on both html and body
- const observer = new MutationObserver(() => {
- setInvertedThemeMode(detectTheme());
- });
-
- observer.observe(document.documentElement, {
- attributes: true,
- attributeFilter: ['data-theme-mode'],
- });
-
- observer.observe(document.body, {
- attributes: true,
- attributeFilter: ['data-theme-mode'],
- });
-
- return () => observer.disconnect();
- }, []);
-
- return invertedThemeMode;
-}
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index 6dc9d5f292..c70aa9d325 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -56,7 +56,6 @@ 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';