From ff3d36435ba71f474572c87b518d68904f3f4540 Mon Sep 17 00:00:00 2001 From: Eskalifer1 Date: Tue, 13 Jan 2026 16:01:38 +0200 Subject: [PATCH 1/3] fix:78318: Hide Table.Header when isEmptyResult is true --- src/components/Table/TableHeader.tsx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/Table/TableHeader.tsx b/src/components/Table/TableHeader.tsx index f105898a33797..22fc2cb8e9100 100644 --- a/src/components/Table/TableHeader.tsx +++ b/src/components/Table/TableHeader.tsx @@ -20,7 +20,10 @@ const NUMBER_OF_TOGGLES_BEFORE_RESET = 2; /** * Props for the TableHeader component. */ -type TableHeaderProps = ViewProps; +type TableHeaderProps = ViewProps & { + /** Hide table header when search returns no results. */ + shouldHideHeaderWhenEmptySearch?: boolean; +}; /** * Renders the table header row with sortable column headers. @@ -45,9 +48,24 @@ type TableHeaderProps = ViewProps; * * ``` */ -function TableHeader({style, ...props}: TableHeaderProps) { +function TableHeader({style, shouldHideHeaderWhenEmptySearch = true, ...props}: TableHeaderProps) { const styles = useThemeStyles(); - const {columns} = useTableContext(); + const {columns, processedData: filteredAndSortedData, originalDataLength, activeSearchString, activeFilters, filterConfig} = useTableContext(); + + const hasActiveFilters = filterConfig + ? Object.keys(activeFilters).some((key) => { + const filterValue = activeFilters[key]; + const defaultValue = filterConfig?.[key]?.default; + return filterValue !== defaultValue; + }) + : false; + + const hasSearchString = activeSearchString.trim().length > 0; + const isEmptyResult = filteredAndSortedData.length === 0 && originalDataLength > 0 && (hasSearchString || hasActiveFilters); + + if (shouldHideHeaderWhenEmptySearch && isEmptyResult) { + return null; + } return ( Date: Tue, 13 Jan 2026 17:22:16 +0200 Subject: [PATCH 2/3] feat: refactor code to use context values instead of duplicate --- src/components/Table/Table.tsx | 19 ++++++++++++++++++- src/components/Table/TableBody.tsx | 14 +------------- src/components/Table/TableContext.tsx | 12 ++++++++++++ src/components/Table/TableHeader.tsx | 13 +------------ 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index d79957d9085aa..34ffc388a7615 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -175,18 +175,35 @@ function Table; }); + const originalDataLength = data?.length ?? 0; + + // Check if filters are applied (not default values) + const hasActiveFilters = filters + ? (Object.keys(currentFilters) as Array).some((key) => { + const filterValue = currentFilters[key]; + const defaultValue = filters[key]?.default; + return filterValue !== defaultValue; + }) + : false; + + const hasSearchString = activeSearchString.trim().length > 0; + const isEmptyResult = processedData.length === 0 && originalDataLength > 0 && (hasSearchString || hasActiveFilters); + // eslint-disable-next-line react/jsx-no-constructed-context-values const contextValue: TableContextValue = { listRef, listProps, processedData, - originalDataLength: data?.length ?? 0, + originalDataLength, columns, filterConfig: filters, activeFilters: currentFilters, activeSorting, activeSearchString, tableMethods, + hasActiveFilters, + hasSearchString, + isEmptyResult, }; return }>{children}; diff --git a/src/components/Table/TableBody.tsx b/src/components/Table/TableBody.tsx index 893c6624107f4..7db8400bd37fb 100644 --- a/src/components/Table/TableBody.tsx +++ b/src/components/Table/TableBody.tsx @@ -46,21 +46,9 @@ type TableBodyProps = ViewProps & { function TableBody({contentContainerStyle, ...props}: TableBodyProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {processedData: filteredAndSortedData, originalDataLength, activeSearchString, activeFilters, filterConfig, listProps} = useTableContext(); + const {processedData: filteredAndSortedData, activeSearchString, listProps, hasActiveFilters, hasSearchString, isEmptyResult} = useTableContext(); const {ListEmptyComponent, contentContainerStyle: listContentContainerStyle, ...restListProps} = listProps ?? {}; - // Check if filters are applied (not default values) - const hasActiveFilters = filterConfig - ? Object.keys(activeFilters).some((key) => { - const filterValue = activeFilters[key]; - const defaultValue = filterConfig?.[key]?.default; - return filterValue !== defaultValue; - }) - : false; - - const hasSearchString = activeSearchString.trim().length > 0; - const isEmptyResult = filteredAndSortedData.length === 0 && originalDataLength > 0 && (hasSearchString || hasActiveFilters); - // Determine the message based on what caused the empty result const getEmptyMessage = () => { if (hasSearchString) { diff --git a/src/components/Table/TableContext.tsx b/src/components/Table/TableContext.tsx index e03127714067d..136b21f434138 100644 --- a/src/components/Table/TableContext.tsx +++ b/src/components/Table/TableContext.tsx @@ -41,6 +41,15 @@ type TableContextValue; + + /** Whether any filters differ from their default values. */ + hasActiveFilters: boolean; + + /** Whether search string is not empty. */ + hasSearchString: boolean; + + /** Whether the table has an empty result caused by search or filters. */ + isEmptyResult: boolean; }; const defaultTableContextValue: TableContextValue = { @@ -57,6 +66,9 @@ const defaultTableContextValue: TableContextValue = { tableMethods: {} as TableMethods, filterConfig: undefined, listProps: {} as SharedListProps, + hasActiveFilters: false, + hasSearchString: false, + isEmptyResult: false, }; const TableContext = createContext(defaultTableContextValue); diff --git a/src/components/Table/TableHeader.tsx b/src/components/Table/TableHeader.tsx index 22fc2cb8e9100..093a9000ea642 100644 --- a/src/components/Table/TableHeader.tsx +++ b/src/components/Table/TableHeader.tsx @@ -50,18 +50,7 @@ type TableHeaderProps = ViewProps & { */ function TableHeader({style, shouldHideHeaderWhenEmptySearch = true, ...props}: TableHeaderProps) { const styles = useThemeStyles(); - const {columns, processedData: filteredAndSortedData, originalDataLength, activeSearchString, activeFilters, filterConfig} = useTableContext(); - - const hasActiveFilters = filterConfig - ? Object.keys(activeFilters).some((key) => { - const filterValue = activeFilters[key]; - const defaultValue = filterConfig?.[key]?.default; - return filterValue !== defaultValue; - }) - : false; - - const hasSearchString = activeSearchString.trim().length > 0; - const isEmptyResult = filteredAndSortedData.length === 0 && originalDataLength > 0 && (hasSearchString || hasActiveFilters); + const {columns, isEmptyResult} = useTableContext(); if (shouldHideHeaderWhenEmptySearch && isEmptyResult) { return null; From 573260e02b53b556e5a18927a309d512b4df9557 Mon Sep 17 00:00:00 2001 From: Eskalifer1 Date: Tue, 13 Jan 2026 17:23:47 +0200 Subject: [PATCH 3/3] fix eslint --- src/components/Table/Table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 34ffc388a7615..3e88e5ce281c9 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -179,7 +179,7 @@ function Table).some((key) => { + ? (Object.keys(currentFilters) as FilterKey[]).some((key) => { const filterValue = currentFilters[key]; const defaultValue = filters[key]?.default; return filterValue !== defaultValue;