Skip to content

Conversation

@dmytrokirpa
Copy link
Contributor

@dmytrokirpa dmytrokirpa commented Jan 15, 2026

Previous Behavior

New Behavior

Added use${Component}Base__unstable hook for every component that contains state for logic, slots (but not default implementations), but not design-related props as per #35623. Exports are commented out intentionally, as we'll uncomment them in experimental branch for experimental release.

Example how to compose a custom Toolbar component:

import * as React from 'react';
import { renderButton_unstable } from '@fluentui/react-button';
import { renderDivider_unstable } from '@fluentui/react-divider';
import type {
  ToolbarBaseProps,
  ToolbarButtonBaseProps,
  ToolbarButtonState,
  ToolbarDividerBaseProps,
  ToolbarDividerState,
  ToolbarState,
} from '@fluentui/react-toolbar';
import {
  renderToolbar_unstable,
  useToolbarBase_unstable,
  useToolbarButtonBase_unstable,
  useToolbarContext_unstable,
  useToolbarContextValues_unstable,
  useToolbarDividerBase_unstable,
} from '@fluentui/react-toolbar';

type ToolbarSize = 'small' | 'large';

type ToolbarProps = ToolbarBaseProps & {
  size?: ToolbarSize;
};

const Toolbar = React.forwardRef<HTMLDivElement, ToolbarProps>(({ size = 'small', ...props }, ref) => {
  const state = useToolbarBase_unstable(props, ref);
  const contextValues = useToolbarContextValues_unstable({ size, ...state });

  state.root.className = ['toolbar', state.root.className].filter(Boolean).join(' ');

  return renderToolbar_unstable(state as ToolbarState, contextValues);
});

const ToolbarButton = React.forwardRef<HTMLButtonElement, ToolbarButtonBaseProps>((props, ref) => {
  const state = useToolbarButtonBase_unstable(props, ref);

  const size = useToolbarContext_unstable(ctx => ctx.size as ToolbarSize);

  state.root.className = ['toolbar__button', `toolbar__button--${size}`, state.root.className]
    .filter(Boolean)
    .join(' ');

  return renderButton_unstable(state as ToolbarButtonState);
});

const ToolbarDivider = React.forwardRef<HTMLElement, ToolbarDividerBaseProps>((props, ref) => {
  const state = useToolbarDividerBase_unstable(props, ref);

  state.root.className = ['toolbar__divider', state.root.className].filter(Boolean).join(' ');

  return renderDivider_unstable(state as ToolbarDividerState);
});

const Example = (): React.ReactNode => (
  <Toolbar size="small" aria-label="Toolbar example with buttons and divider">
    <ToolbarButton aria-label="First" icon={1} />
    <ToolbarButton aria-label="Second" icon={1} />
    <ToolbarDivider />
    <ToolbarButton aria-label="Third" icon={1}>
      3
    </ToolbarButton>
  </Toolbar>
);

Note: There are no public API changes or modifications to the behavior of existing components, and all unit and VR tests are passing. The two existing hooks, useToolbarContextValues_unstable and useToolbarContext_unstable now exported for composing custom components.

Related Issue(s)

@github-actions
Copy link

github-actions bot commented Jan 15, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-components
react-components: entire library
1.286 MB
322.184 kB
1.287 MB
322.322 kB
335 B
138 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-components
react-components: Button, FluentProvider & webLightTheme
70.309 kB
20.074 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
237.447 kB
68.609 kB
react-components
react-components: FluentProvider & webLightTheme
43.608 kB
14.165 kB
react-portal-compat
PortalCompatProvider
8.386 kB
2.624 kB
react-timepicker-compat
TimePicker
109.023 kB
36.011 kB
🤖 This report was generated against aa4c072a894b8d9e70c3e749ee7851e3c18ce63c

@github-actions
Copy link

Pull request demo site: URL

@dmytrokirpa dmytrokirpa force-pushed the feat/toolbar-base-hooks branch from cc4d54f to 3720285 Compare January 15, 2026 11:35
@@ -0,0 +1,7 @@
{
Copy link

@github-actions github-actions bot Jan 15, 2026

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Charts-DonutChart 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 5581 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic - Dark Mode.default.chromium.png 7530 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 745 Changed
vr-tests-react-components/Positioning.Positioning end.chromium.png 611 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled.chromium.png 677 Changed

There were 1 duplicate changes discarded. Check the build logs for more information.

@dmytrokirpa dmytrokirpa marked this pull request as ready for review January 15, 2026 12:37
@dmytrokirpa dmytrokirpa requested review from a team and chpalac as code owners January 15, 2026 12:37
@dmytrokirpa dmytrokirpa force-pushed the feat/toolbar-base-hooks branch from 3720285 to b060ef0 Compare January 15, 2026 12:40
@dmytrokirpa dmytrokirpa marked this pull request as draft January 15, 2026 17:01
@dmytrokirpa dmytrokirpa force-pushed the feat/toolbar-base-hooks branch from b060ef0 to b9adbc1 Compare January 19, 2026 20:43
@dmytrokirpa dmytrokirpa marked this pull request as ready for review January 19, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant