diff --git a/projects/packages/premium-analytics/changelog/update-pa-chart-empty-state-detail-widgets b/projects/packages/premium-analytics/changelog/update-pa-chart-empty-state-detail-widgets
new file mode 100644
index 000000000000..c5e6c59c7560
--- /dev/null
+++ b/projects/packages/premium-analytics/changelog/update-pa-chart-empty-state-detail-widgets
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Dashboard: Show the no-results message in the Post views, Author performance, Video views and Store performance charts for a period with no data, instead of a flat zero line.
diff --git a/projects/packages/premium-analytics/widgets/author-performance/__tests__/author-performance.test.tsx b/projects/packages/premium-analytics/widgets/author-performance/__tests__/author-performance.test.tsx
index cb3c915e547c..3824166bd4e6 100644
--- a/projects/packages/premium-analytics/widgets/author-performance/__tests__/author-performance.test.tsx
+++ b/projects/packages/premium-analytics/widgets/author-performance/__tests__/author-performance.test.tsx
@@ -4,6 +4,7 @@
import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/data';
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
+import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
@@ -18,6 +19,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
+ empty,
}: {
metrics: {
key: string;
@@ -27,6 +29,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
countLabel?: ( count: number ) => string;
}[];
chartType?: string;
+ empty?: ReactNode;
} ) => (
( {
dates: metric.current.map( point => point.date.toISOString().slice( 0, 10 ) ),
} ) )
) }
- />
+ >
+ { empty }
+
),
} ) );
@@ -200,6 +205,19 @@ describe( 'AuthorPerformanceWidget', () => {
);
} );
+ it( 'shows the no-results message in the chart for a window without views', async () => {
+ mockApiFetch.mockResolvedValue( {
+ ...TOP_AUTHORS_DAYS,
+ days: { '2026-07-02': TOP_AUTHORS_DAYS.days[ '2026-07-02' ] },
+ } );
+
+ render( );
+
+ await expect(
+ screen.findByText( 'We couldn’t find results for this time period.' )
+ ).resolves.toBeInTheDocument();
+ } );
+
it( 'renders the scopeless empty state and makes no request without an author scope', async () => {
render( );
diff --git a/projects/packages/premium-analytics/widgets/author-performance/render.tsx b/projects/packages/premium-analytics/widgets/author-performance/render.tsx
index 89bd7e04e91c..e8b6692c5d00 100644
--- a/projects/packages/premium-analytics/widgets/author-performance/render.tsx
+++ b/projects/packages/premium-analytics/widgets/author-performance/render.tsx
@@ -4,6 +4,7 @@
import { STATS_CHART_BUCKET_PERIODS, toAuthorId } from '@jetpack-premium-analytics/data';
import { reports } from '@jetpack-premium-analytics/icons';
import {
+ ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
@@ -97,6 +98,7 @@ function AuthorPerformanceInner( { chartType }: AuthorPerformanceInnerProps ) {
metrics={ metricTabs }
dataFormat={ DATA_FORMAT }
chartType={ chartType }
+ empty={ }
/>
diff --git a/projects/packages/premium-analytics/widgets/post-views/__tests__/post-views.test.tsx b/projects/packages/premium-analytics/widgets/post-views/__tests__/post-views.test.tsx
index 0c821939b561..2acb485fe26b 100644
--- a/projects/packages/premium-analytics/widgets/post-views/__tests__/post-views.test.tsx
+++ b/projects/packages/premium-analytics/widgets/post-views/__tests__/post-views.test.tsx
@@ -5,6 +5,7 @@ import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/d
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
import { getSettings, setSettings } from '@wordpress/date';
+import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
@@ -19,6 +20,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
+ empty,
}: {
metrics: {
key: string;
@@ -29,6 +31,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
dataFormat?: { type: string };
}[];
chartType?: string;
+ empty?: ReactNode;
} ) => (
( {
days: metric.current.map( point => point.date.getDate() ),
} ) )
) }
- />
+ >
+ { empty }
+
),
} ) );
@@ -200,6 +205,16 @@ describe( 'PostViewsWidget', () => {
expect( mockApiFetch ).toHaveBeenCalledTimes( 1 );
} );
+ it( 'shows the no-results message in the chart for a window without views', async () => {
+ mockApiFetch.mockResolvedValue( { data: [] } );
+
+ render( );
+
+ await expect(
+ screen.findByText( 'We couldn’t find results for this time period.' )
+ ).resolves.toBeInTheDocument();
+ } );
+
it( 'renders the scopeless empty state and makes no request without a post scope', async () => {
render( );
diff --git a/projects/packages/premium-analytics/widgets/post-views/render.tsx b/projects/packages/premium-analytics/widgets/post-views/render.tsx
index 3002862f8a75..1ea46713463e 100644
--- a/projects/packages/premium-analytics/widgets/post-views/render.tsx
+++ b/projects/packages/premium-analytics/widgets/post-views/render.tsx
@@ -4,6 +4,7 @@
import { STATS_CHART_BUCKET_PERIODS, toPostId } from '@jetpack-premium-analytics/data';
import { reports } from '@jetpack-premium-analytics/icons';
import {
+ ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
@@ -97,6 +98,7 @@ function PostViewsInner( { chartType }: PostViewsInnerProps ) {
metrics={ metricTabs }
dataFormat={ DATA_FORMAT }
chartType={ chartType }
+ empty={ }
/>
diff --git a/projects/packages/premium-analytics/widgets/store-performance/__tests__/render.test.tsx b/projects/packages/premium-analytics/widgets/store-performance/__tests__/render.test.tsx
new file mode 100644
index 000000000000..6b0fc687c155
--- /dev/null
+++ b/projects/packages/premium-analytics/widgets/store-performance/__tests__/render.test.tsx
@@ -0,0 +1,50 @@
+/**
+ * External dependencies
+ */
+import { render, screen } from '@testing-library/react';
+import type { ReactNode } from 'react';
+/**
+ * Internal dependencies
+ */
+import StorePerformanceRender from '../render';
+
+const mockEmptyReport = {
+ primary: { data: { summary: {}, data: [] } },
+ comparison: { data: { summary: {}, data: [] } },
+ timezone: 'UTC',
+ isLoading: false,
+ isFetching: false,
+ isError: false,
+ hasData: false,
+ refetch: jest.fn(),
+};
+
+jest.mock( '@jetpack-premium-analytics/data', () => ( {
+ ...jest.requireActual( '@jetpack-premium-analytics/data' ),
+ useReportOrders: () => mockEmptyReport,
+ useReportVisitors: () => mockEmptyReport,
+ useReportConversionRate: () => mockEmptyReport,
+ useReportCustomersByDate: () => mockEmptyReport,
+} ) );
+
+// The chart itself is visx SVG rendering, outside this widget's concern.
+jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
+ ...jest.requireActual( '@jetpack-premium-analytics/widgets-toolkit' ),
+ MetricTabsChart: ( { empty }: { empty?: ReactNode } ) => (
+ { empty }
+ ),
+} ) );
+
+// WidgetRoot reads URL search params as a fallback for report params; outside
+// a matched route the real hook warns and throws.
+jest.mock( '@wordpress/route', () => jest.requireActual( '../../test-utils' ).mockWordPressRoute );
+
+describe( 'StorePerformanceRender', () => {
+ it( 'shows the no-results message in the chart for a store without orders or visits', () => {
+ render( );
+
+ expect(
+ screen.getByText( 'We couldn’t find results for this time period.' )
+ ).toBeInTheDocument();
+ } );
+} );
diff --git a/projects/packages/premium-analytics/widgets/store-performance/render.tsx b/projects/packages/premium-analytics/widgets/store-performance/render.tsx
index 57e91c5d732f..4b58b9b5ecf9 100644
--- a/projects/packages/premium-analytics/widgets/store-performance/render.tsx
+++ b/projects/packages/premium-analytics/widgets/store-performance/render.tsx
@@ -7,6 +7,7 @@ import {
} from '@jetpack-premium-analytics/data';
import {
BOOKINGS_FILTER,
+ ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
@@ -361,6 +362,7 @@ function StorePerformanceContent() {
metrics={ metricTabs }
dataFormat={ DEFAULT_DATA_FORMAT }
groupLabel={ __( 'Store metric', 'jetpack-premium-analytics-pkg' ) }
+ empty={ }
/>
diff --git a/projects/packages/premium-analytics/widgets/video-detail-views-performance/__tests__/video-detail-views-performance.test.tsx b/projects/packages/premium-analytics/widgets/video-detail-views-performance/__tests__/video-detail-views-performance.test.tsx
index 07c149caad23..aa54e8ca91e5 100644
--- a/projects/packages/premium-analytics/widgets/video-detail-views-performance/__tests__/video-detail-views-performance.test.tsx
+++ b/projects/packages/premium-analytics/widgets/video-detail-views-performance/__tests__/video-detail-views-performance.test.tsx
@@ -4,6 +4,7 @@
import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/data';
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
+import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
@@ -18,6 +19,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
+ empty,
}: {
metrics: {
key: string;
@@ -28,6 +30,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
dataFormat?: { type: string };
}[];
chartType?: string;
+ empty?: ReactNode;
} ) => (
( {
days: metric.current.map( point => point.date.getDate() ),
} ) )
) }
- />
+ >
+ { empty }
+
),
} ) );
@@ -321,6 +326,16 @@ describe( 'VideoDetailViewsPerformanceWidget', () => {
expect( metrics[ 0 ].value ).toBe( 12 );
} );
+ it( 'shows the no-results message in the chart for a window without views', async () => {
+ mockApiFetch.mockImplementation( respondByWindow( {} ) );
+
+ render( );
+
+ await expect(
+ screen.findByText( 'We couldn’t find results for this time period.' )
+ ).resolves.toBeInTheDocument();
+ } );
+
it( 'renders the scopeless empty state and makes no request without a video scope', async () => {
render( );
diff --git a/projects/packages/premium-analytics/widgets/video-detail-views-performance/render.tsx b/projects/packages/premium-analytics/widgets/video-detail-views-performance/render.tsx
index f305b4c1be81..d1382d389fc1 100644
--- a/projects/packages/premium-analytics/widgets/video-detail-views-performance/render.tsx
+++ b/projects/packages/premium-analytics/widgets/video-detail-views-performance/render.tsx
@@ -3,6 +3,7 @@
*/
import { STATS_CHART_BUCKET_PERIODS, toPostId } from '@jetpack-premium-analytics/data';
import {
+ ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
@@ -81,6 +82,7 @@ function VideoDetailViewsPerformanceInner( { chartType }: VideoDetailViewsPerfor
dataFormat={ COUNT_FORMAT }
chartType={ chartType }
groupLabel={ groupLabel }
+ empty={ }
/>