diff --git a/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx b/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx
index 0cf69b7dd..d40e801dd 100644
--- a/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx
+++ b/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx
@@ -62,6 +62,7 @@ import {useStackedData} from './hooks';
import {StackedAreas, Points} from './components';
import {useStackedChartTooltipContent} from './hooks/useStackedChartTooltipContent';
import {yAxisMinMax} from './utilities/yAxisMinMax';
+import {getAlteredStackedAreaChartPosition} from './utilities/getAlteredStackedAreaChartPosition';
import styles from './Chart.scss';
const TOOLTIP_POSITION: TooltipPositionOffset = {
@@ -382,6 +383,7 @@ export function Chart({
focusElementDataType={DataType.Point}
getMarkup={getTooltipMarkup}
getPosition={getTooltipPosition}
+ getAlteredPosition={getAlteredStackedAreaChartPosition}
id={tooltipId}
margin={ChartMargin}
onIndexChange={(index) => setActivePointIndex(index)}
diff --git a/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx b/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx
new file mode 100644
index 000000000..9f421a225
--- /dev/null
+++ b/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx
@@ -0,0 +1,40 @@
+import type {Story} from '@storybook/react';
+
+export {META as default} from './meta';
+
+import {StackedAreaChart, type StackedAreaChartProps} from '../../../components';
+
+import {DEFAULT_DATA, DEFAULT_PROPS} from './data';
+
+function Card(args: StackedAreaChartProps) {
+ return (
+
+
+
+ );
+}
+
+const Template: Story = (args: StackedAreaChartProps) => {
+ return (
+
+ );
+}
+
+
+
+export const ExternalTooltip: Story = Template.bind({});
+
+ExternalTooltip.args = {
+ ...DEFAULT_PROPS,
+ data: DEFAULT_DATA,
+};
diff --git a/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts b/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts
new file mode 100644
index 000000000..b01023770
--- /dev/null
+++ b/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts
@@ -0,0 +1,54 @@
+import type {Dimensions} from '@shopify/polaris-viz-core';
+
+import type {TooltipPositionOffset} from '../../TooltipWrapper';
+import type {Margin} from '../../../types';
+
+// The space between the cursor and the tooltip
+const TOOLTIP_MARGIN = 20;
+
+export interface AlteredPositionProps {
+ bandwidth: number;
+ chartBounds: {x: number; y: number; width: number; height: number};
+ currentX: number;
+ currentY: number;
+ isPerformanceImpacted: boolean;
+ margin: Margin;
+ position: TooltipPositionOffset;
+ tooltipDimensions: Dimensions;
+}
+
+export interface AlteredPositionReturn {
+ x: number;
+ y: number;
+}
+
+export type AlteredPosition = (
+ props: AlteredPositionProps,
+) => AlteredPositionReturn;
+
+export function getAlteredStackedAreaChartPosition({
+ currentX,
+ currentY,
+ chartBounds,
+ margin,
+ tooltipDimensions,
+}: AlteredPositionProps): AlteredPositionReturn {
+ const x = Math.min(
+ Math.max(currentX, TOOLTIP_MARGIN),
+ chartBounds.width - tooltipDimensions.width - TOOLTIP_MARGIN,
+ );
+
+ // Y POSITIONING
+ // If y is below the chart, adjust the tooltip position to the bottom of the chart
+ //
+
+ const y =
+ currentY >= chartBounds.y + chartBounds.height
+ ? chartBounds.height -
+ tooltipDimensions.height -
+ TOOLTIP_MARGIN -
+ margin.Bottom
+ : currentY;
+
+ return {x, y};
+}
diff --git a/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts b/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts
new file mode 100644
index 000000000..c01005e5b
--- /dev/null
+++ b/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts
@@ -0,0 +1,80 @@
+import type {AlteredPositionProps} from '../../../TooltipWrapper';
+import {
+ TooltipVerticalOffset,
+ TooltipHorizontalOffset,
+} from '../../../TooltipWrapper';
+import {getAlteredStackedAreaChartPosition} from '../getAlteredStackedAreaChartPosition';
+
+const MARGIN = {Top: 0, Left: 0, Right: 0, Bottom: 0};
+const TOOLTIP_MARGIN = 20;
+
+const BASE_PROPS: AlteredPositionProps = {
+ isPerformanceImpacted: false,
+ chartBounds: {height: 100, width: 200, x: 0, y: 100},
+ tooltipDimensions: {height: 40, width: 60},
+ margin: MARGIN,
+ bandwidth: 40,
+ currentX: 20,
+ currentY: 0,
+ position: {
+ horizontal: TooltipHorizontalOffset.Left,
+ vertical: TooltipVerticalOffset.Center,
+ },
+};
+
+describe('getAlteredStackedAreaChartPosition', () => {
+ it('returns the original position of y when currentY is within the chart bounds', () => {
+ const props = {
+ ...BASE_PROPS,
+ currentX: 50,
+ currentY: 50,
+ };
+
+ const result = getAlteredStackedAreaChartPosition(props);
+
+ expect(result.x).toBe(50);
+ expect(result.y).toBe(50);
+ });
+
+ it('returns the adjusted position when currentY is greater than chartBounds.y + chartBounds.height', () => {
+ const props = {
+ ...BASE_PROPS,
+ currentY: 300,
+ };
+
+ const chartBounds = props.chartBounds;
+ const tooltipDimensions = props.tooltipDimensions;
+ const margin = props.margin;
+ const result = getAlteredStackedAreaChartPosition(props);
+
+ expect(result.x).toBe(20);
+
+ expect(result.y).toBe(
+ chartBounds.height -
+ tooltipDimensions.height -
+ TOOLTIP_MARGIN -
+ margin.Bottom,
+ );
+ });
+
+ it('returns the adjusted position when currentY is equal to chartBounds.y + chartBounds.height', () => {
+ const props = {
+ ...BASE_PROPS,
+ currentY: 200,
+ };
+
+ const chartBounds = props.chartBounds;
+ const tooltipDimensions = props.tooltipDimensions;
+ const margin = props.margin;
+ const result = getAlteredStackedAreaChartPosition(props);
+
+ expect(result.x).toBe(20);
+
+ expect(result.y).toBe(
+ chartBounds.height -
+ tooltipDimensions.height -
+ TOOLTIP_MARGIN -
+ margin.Bottom,
+ );
+ });
+});