Handsontable with Fluent UI
In this tutorial, you will integrate Handsontable into a React app with Fluent UI so your grid follows Fluent colors, typography, and spacing. You will learn how to map Fluent UI tokens to Handsontable theme parameters through the Theme API.
Overview
This recipe shows how to integrate Handsontable into a React app that uses Fluent UI by registering a custom theme with Theme API colors and tokens. The grid follows your Fluent design language.
Difficulty: Beginner
Time: ~15 minutes
Stack: React, Fluent UI, Handsontable, @handsontable/react-wrapper
What You’ll Get
- A reusable Handsontable theme (
registerTheme('fluent-data-grid', { icons, colors, tokens })) that maps to Fluent UI colors. - A React grid component that applies Fluent-like typography (
Segoe UI), neutral table colors, and roomier cell paddings. - A working baseline you can extend with dark mode and custom icon overrides.
Prerequisites
- A React app with Fluent UI configured.
- Handsontable and the React wrapper installed.
- A
FluentProviderat your app root.
Install dependencies with pinned Handsontable versions
Terminal window npm install handsontable @handsontable/react-wrapper @fluentui/react-componentsWrap your app in FluentProvider
Fluent UI tokens are available through the provider. Use
webLightTheme,webDarkTheme, or your own custom theme.import { FluentProvider, webLightTheme } from '@fluentui/react-components';export function AppRoot() {return (<FluentProvider theme={webLightTheme}><App /></FluentProvider>);}Create Fluent color mapping for Theme API
Handsontable’s Theme API expects the
palette,primary,white,black, andtransparentstructure.File:
src/theme/colorsFluent.tsconst colorsFluent = {palette: {50: 'var(--colorNeutralBackground1)',100: 'var(--colorNeutralBackground2)',200: 'var(--colorNeutralBackground3)',300: 'var(--colorNeutralBackground4)',400: 'var(--colorNeutralStroke1)',500: 'var(--colorNeutralStroke2)',600: 'var(--colorNeutralForeground3)',700: 'var(--colorNeutralForeground2)',800: 'var(--colorNeutralForeground1)',900: 'var(--colorNeutralForegroundOnBrand)',950: 'var(--colorNeutralForegroundOnBrand)',},primary: {100: 'var(--colorBrandBackground)',200: 'var(--colorBrandBackground2)',300: 'var(--colorBrandBackgroundInverted)',400: 'var(--colorBrandStroke1)',500: 'var(--colorBrandForeground1)',600: 'var(--colorBrandForeground2)',},white: 'var(--colorNeutralBackground1)',black: 'var(--colorNeutralForeground1)',transparent: 'transparent',};export default colorsFluent;Register your Fluent Handsontable theme
Import
iconstogether withcolorsandtokens.registerTheme()requiresicons- if omitted, ThemeBuilder throws an error.import { registerTheme } from 'handsontable/themes';import iconsHorizon from 'handsontable/themes/static/variables/icons/horizon';import tokensHorizon from 'handsontable/themes/static/variables/tokens/horizon';import colorsFluent from './theme/colorsFluent';export const fluentDataGridTheme = registerTheme('fluent-data-grid', {icons: iconsHorizon,colors: colorsFluent,tokens: tokensHorizon,}).params({tokens: {fontFamily: "'Segoe UI', 'Segoe UI Web (West European)', system-ui, sans-serif",fontSize: '14px',lineHeight: '20px',headerFontWeight: '600',foregroundColor: '#242424',foregroundSecondaryColor: '#616161',backgroundColor: '#ffffff',backgroundSecondaryColor: '#fafafa',borderColor: '#e1dfdd',cellVerticalBorderColor: '#e1dfdd',headerBackgroundColor: '#f5f5f5',headerForegroundColor: '#242424',rowCellOddBackgroundColor: '#ffffff',rowCellEvenBackgroundColor: '#ffffff',rowHeaderOddBackgroundColor: '#ffffff',rowHeaderEvenBackgroundColor: '#ffffff',cellHorizontalPadding: '12px',cellVerticalPadding: '10px',barHorizontalPadding: '12px',barVerticalPadding: '8px',menuItemHorizontalPadding: '12px',menuItemVerticalPadding: '8px',wrapperBorderRadius: '8px',cellSelectionBorderColor: '#0f6cbd',cellSelectionBackgroundColor: '#deecf9',},});Build a themed grid component
Register modules, apply the theme, import Handsontable CSS, and render a minimal table.
File:
src/components/FluentHotTable.tsximport { HotTable, HotColumn } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';import 'handsontable/styles/handsontable.min.css';import 'handsontable/styles/ht-theme-horizon.min.css';import { fluentDataGridTheme } from '../theme/fluentDataGridTheme';registerAllModules();const data = [{ team: 'Design', owner: 'Ava', status: 'In progress', priority: 'High' },{ team: 'Platform', owner: 'Noah', status: 'Blocked', priority: 'Medium' },{ team: 'Docs', owner: 'Liam', status: 'Done', priority: 'Low' },];export default function FluentHotTable() {return (<HotTabletheme={fluentDataGridTheme}data={data}colHeaders={['Team', 'Owner', 'Status', 'Priority']}rowHeaders={true}width="100%"height="auto"dropdownMenu={true}filters={true}licenseKey="non-commercial-and-evaluation"><HotColumn data="team" width={180} /><HotColumn data="owner" width={140} /><HotColumn data="status" width={160} /><HotColumn data="priority" width={140} /></HotTable>);}Render inside FluentProvider
Wrap your app with Fluent’s provider, then render the table component.
import { FluentProvider, webLightTheme } from '@fluentui/react-components';import FluentHotTable from './components/FluentHotTable';export default function App() {return (<FluentProvider theme={webLightTheme}><FluentHotTable /></FluentProvider>);}
Optional enhancements
- Switch to
webDarkThemeand tune Theme API token overrides for dark mode. - Override additional Theme API tokens (for example, header colors, cell selection, and spacing).
- Replace
iconsHorizonwith your own icon set while keeping all required icon keys.
What you learned
- How to read Fluent UI design token values and map them to Handsontable Theme API parameters to align colors, typography, and spacing.
- How to wrap the Handsontable grid in a
FluentProviderso it receives the correct theme context alongside other Fluent components. - How to switch between
webLightThemeandwebDarkThemeand update the Handsontable theme in the same render cycle. - How to replace the default Handsontable icon set with Fluent icons using the
iconsHorizonicon key structure.
Next steps
- Explore Handsontable with Ant Design for the same token-mapping approach with Ant Design.
- Explore Handsontable with MUI for Material UI integration.
Related
- Themes - Built-in themes and Theme API.
- Theme customization - Theme API parameters and CSS variable reference.
- Theme Recipes - Practical design-system recipes for Handsontable.