React Components include Bootstrap and Material-UI themes that can be customized. However, there are situations when you want to develop a custom theme. For example, when your site does not abide by Bootstrap or Material-UI guidelines.
A theme is a set of React UI components that implement the representation logic. All the internal routines are encapsulated in plugins and contained in core packages: dx-react-grid
, dx-react-scheduler
, and dx-react-chart
. A core package exports "bare" UI plugins that a theme package can fill with visual components via Render Props. To stylize such a plugin, you should provide necessary theme components to it.
In this tutorial, we create a grid theme based on the Semantic UI framework. This theme stylizes three main plugins: Grid, Table, and TableHeader. Theme sources and preview are available in this CodeSandbox.
The theme consists of two directories: plugins
(plugins that we customize) and templates
(components provided to the plugins). Both of them are located in the semantic-ui-theme
directory under src
.
As we mentioned earlier, plugins render UI elements via render props. All render props have the postfix Component
. For instance, the Table plugin contains the tableComponent
, headComponent
, cellComponent
, and others.
If props are of the object
type, you can pass them to the theme component "as is":
import { Table as TableSUI } from 'semantic-ui-react';
const TableHead = props => <TableSUI.Header {...props} />;
Otherwise, you need to destructure the props. Let's look at the cellComponent
prop of the Table
plugin for example. It receives Table.DataCellProps. Some of them, such as tableColumn
, row
, and value
, are specific to the Grid and unknown to React. They should not be passed to the theme component and need to be removed from the props. The following example illustrates the process:
import { Table as TableSUI } from 'semantic-ui-react';
export const TableCell = ({
tableColumn, tableRow,
column, row,
children, value,
...restProps
}) => (
<TableSUI.Cell
textAlign={tableColumn.align}
singleLine={!tableColumn.wordWrapEnabled}
{...restProps}
>
{ children || value }
</TableSUI.Cell>
);
Once you implement all the required components, create a theme plugin. Inside of it, import a base plugin from the core package and provide your theme components to it:
import { TableHeaderRow as TableHeaderRowBase } from '@devexpress/dx-react-grid';
import { TableRow } from '../templates/table-row';
// ... other components
export const TableHeaderRow = props => (
<TableHeaderRowBase
rowComponent={TableRow}
// ... other components
{...props}
/>
If you look at the code of our themes, you may notice that we do the same with a not-yet-documented HOC, withComponents
. The previous code looks like this if you use this HOC too:
import { withComponents } from '@devexpress/dx-react-core';
import { TableHeaderRow as TableHeaderRowBase } from '@devexpress/dx-react-grid';
import { TableRow } from '../templates/table-row';
// ... other components
export const TableHeaderRow = withComponents({
TableRow,
// ... other components
})(TableHeaderRowBase);
A number of our components, like TableLayout, are still to be documented. When you implement a custom theme, we recommend consulting our repository code as well as the docs.