Skip to content

Fix: Expose contexts in DataTableBase loading and empty states#11144

Open
dreglad wants to merge 1 commit intomarmelab:masterfrom
dreglad:ra-core_DataTableBase-contexts
Open

Fix: Expose contexts in DataTableBase loading and empty states#11144
dreglad wants to merge 1 commit intomarmelab:masterfrom
dreglad:ra-core_DataTableBase-contexts

Conversation

@dreglad
Copy link

@dreglad dreglad commented Feb 1, 2026

This change ensures that custom loading and empty components in DataTableBase have access to relevant table contexts.

This should be fully backwards compatible.

Problem

When providing custom loading or empty components to DataTableBase, these components did not have access to any contexts. Some of these contexts, namely resource, table store, and table config, might be valuable when rendering Empty/Loading states. This lack of access forced developers to pass props manually or duplicate logic if they wanted to use this context within their components.

Solution

Updated DataTableBase in packages/ra-core to wrap the loading and empty rendering logic with the following context providers:

  • DataTableStoreContext.Provider
  • DataTableConfigContext.Provider
  • OptionalResourceContextProvider

This ensures that any component rendered in these slots can access the current resource and configuration from context.

How To Test

I have added a new test file packages/ra-core/src/dataTable/DataTableBase.spec.tsx which covers:

  • Context Availability: Verifies that context is correctly resolved by components rendered in the loading and empty slots.
  • Rendering Logic: Verifies existing behavior (now covered by unit tests):
    • Children are rendered when data is present.
    • The loading component is rendered when pending.
    • The empty component is rendered when no data is present (hiding headers).
    • Data is still displayed while refreshing (fetching but not pending).

This change ensures that custom loading and empty components in DataTable have access to ResourceContext and other standard contexts.

Also added comprehensive unit tests for DataTableBase to verify context availability and correct rendering behavior for empty and refreshing states.
@dreglad dreglad changed the title Fix: Expose contexts in DataTable loading and empty states Fix: Expose contexts in DataTableBase loading and empty states Feb 1, 2026
Copy link
Contributor

@slax57 slax57 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution.

This looks interesting, but could you share real-life examples of empty or loading components which require accessing the DataTable contexts? Apart from the ResourceContext (which in most cases is already defined by the parent List component) I cannot think of good examples where this would be needed.

@dreglad
Copy link
Author

dreglad commented Feb 3, 2026

**slax57 ** left a comment

Hi @slax57, great question!

The main reason for keeping these contexts available during loading and empty states is to allow custom components to stay perfectly aligned with the table configuration without needing manual prop-drilling or direct access to the memory store (internal details).

Here are a few real-life examples where this is useful:

Custom Loading Skeletons

To avoid layout shifts, a skeleton needs to know exactly how many columns to render. It needs access to hasBulkActions (to account for the checkbox column), and hiddenColumns (to skip columns the user has hidden). By accessing DataTableConfigContext and DataTableStoreContext, a loading component can automatically adapt its layout to the current table configuration. This is directly related to this PR: marmelab/shadcn-admin-kit#118

Context-Aware empty Components

Depending on the context, an empty state might want to display different calls to action. For instance, an empty component might want to provide a "Reset filters" button that clears filters when the table was empty due to filters being applied.

Overall architectural consistency

In React-admin, we generally follow the pattern of providing configuration via context to allow for highly customizable and pluggable sub-components. Treating loading and empty states as "first-class citizens" that have access to the table's context ensures they can be as rich and integrated as the data rows themselves.

@slax57
Copy link
Contributor

slax57 commented Feb 3, 2026

Thanks for your reply. You convinced me!

I was also asking to see if we should update the documentation with an example leveraging these new possibilities, but I figure the code example (e.g. with a skeleton) would probably be too complex to be comprehensive, so let's forget about this for now.

Besides your PR to shadcn-admin-kit will probably be a good example too!

Copy link
Contributor

@slax57 slax57 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than that the code LGTM!

Comment on lines +88 to +114
it('should display the empty component instead of the table header when loaded with no data', () => {
render(
<ResourceContextProvider value="posts">
<ListContextProvider
value={
{
...defaultListContext,
data: [],
total: 0,
isPending: false,
} as any
}
>
<DataTableBase
empty={<div>Empty Component</div>}
loading={<div>Loading</div>}
hasBulkActions={false}
>
<div>Table Header and Body</div>
</DataTableBase>
</ListContextProvider>
</ResourceContextProvider>
);

expect(screen.queryByText('Empty Component')).not.toBeNull();
expect(screen.queryByText('Table Header and Body')).toBeNull();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks duplicate of test at line 46. If confirmed can you remove it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants