Back to Fluentui

SplitButton component Migration guide

apps/public-docsite-v9/src/Concepts/Migration/FromV0/Components/SplitButton.mdx

4.40.2-hotfix212.9 KB
Original Source

import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Concepts/Migration/from v0/Components/SplitButton Migration" />

SplitButton component Migration guide

SplitButton is now a combination of following components: Menu, MenuTrigger, SplitButton, MenuPopover, MenuList and MenuItem.

Overview:

Before:

tsx
import { SplitButton } from '@fluentui/react-northstar';
const Component = ({ menuItems }) => (
  <SplitButton
    menu={menuItems}
    button={{
      content: 'Split button',
    }}
    onMainButtonClick={() => alert('button was clicked')}
  />
);

After:

tsx
import {
  Menu,
  MenuButtonProps,
  MenuItem,
  MenuList,
  MenuPopover,
  MenuTrigger,
  SplitButton,
} from '@fluentui/react-components';
const Component = ({ menuItems }) => (
  <Menu positioning="below-end">
    <MenuTrigger>
      {(triggerProps: MenuButtonProps) => (
        <SplitButton primaryActionButton={{ onClick: () => alert('button clicked') }} menuButton={triggerProps}>
          Split button
        </SplitButton>
      )}
    </MenuTrigger>

    <MenuPopover>
      <MenuList>
        {menuItems.map(item => (
          <MenuItem key={item.key}>{item.content}</MenuItem>
        ))}
      </MenuList>
    </MenuPopover>
  </Menu>
);

More examples: Sandbox

How to migrate props:

SplitButton propsmigrate guide
accessibilityIn V0, we recommended to use `aria-roledescription` and `aria-describedby` on a `button` slot. This is no longer needed in V9 as a `SplitButton` in V9 is two tabs stop. Also see this a11y migration doc: [migrate-custom-accessibility.md](?path=/docs/concepts-migration-from-v0-custom-accessibility--docs)
as, classNamekeep it as is
align, autoSizeuse `positioning` on `Menu` component; see [Migrate positioning props](../migrate-positioning.md)
buttonuse `primaryActionButton` instead
contentsee [Migrate content prop](##migrate-content-prop) in this document
defaultOpenmove `defaultOpen` prop to `Menu` component
disabledkeep it as is
flatuse `appearance` prop with `outline` as a value
flipBoundary, overflowBoundaryuse `positioning` on `Menu` component; see [Migrate positioning props](../migrate-positioning.md)
menureplace with `MenuItem` wrapped in `MenuList` and `MenuPopover`
offsetuse `positioning` on `Menu` component; see [Migrate positioning props](../migrate-positioning.md)
onMainButtonClickadd `primaryActionButton` prop with `onClick`
onMenuItemClickuse `onClick` on `MenuItem`
onOpenChangeuse `onOpenChange` on `Menu` component
openuse this prop on `Menu` component
position, positionFixeduse `positioning` on `Menu` component; see [Migrate positioning props](../migrate-positioning.md)
primaryuse `appearance` prop with `primary` as a value
secondaryit's the default value without any prop needed
sizekeep it as is
toggleButtonuse `ToggleButton` component
variables, styles, designsee [Migrate style overrides](#migrate-style-overrides) in this document
unstable_disableTether, unstable_pinneduse `positioning` on `Menu` component

Postioning props: align, autoSize, flipBoundary, offset,overflowBoundary,popperRef,position,positionFixed,target, unstable_disableTether, unstable_pinned are now attributes of the positioning prop. V9 positioning shorthand is recommended when only positon or/and align is used: <MenuButton position="below" align="end" /> can be migrate to a string like <Menu positioning="below-end" />. See Migrate positioning props for more.

Here is comparison for both versions: Sandbox


Migrate style overrides

⚠️ If this is your first migration, please read the general guide on how to migrate styles.

Example for migrate boolean variables:

Before:

tsx
// in COMPONENT_NAME.tsx
import { SplitButton } from '@fluentui/react-northstar';

export const Component = ({ menuItems }) => (
  <SplitButton
    menu={menuItems}
    button={{
      content: 'Split button',
    }}
    onMainButtonClick={() => alert('button was clicked')}
    variables={{ isActionButton: true }}
  />
);

// in split-button-styles.ts
export const splitButtonStyles1 = {
  root: ({ variables: { colorSchemeDefault, isActionButton } }) => ({
    ...(isActionButton && {
      color: colorSchemeDefault.foreground,
    }),
  }),
};

After:

tsx
// in COMPONENT_NAME.tsx
import {
  Button,
  Menu,
  MenuButtonProps,
  MenuItem,
  MenuList,
  MenuPopover,
  MenuTrigger,
  SplitButton,
} from '@fluentui/react-components';
import { useStyles } from './COMPONENT_NAME.styles.ts';

export const Component = () => {
  const classes = useStyles();
  return (
    <Menu positioning="below-end">
      <MenuTrigger>
        {(triggerProps: MenuButtonProps) => (
          <SplitButton
            className={classes.actionButton}
            menuButton={triggerProps}
            primaryActionButton={{ onClick: () => alert('button clicked') }}
          >
            Split button
          </SplitButton>
        )}
      </MenuTrigger>

      <MenuPopover>
        <MenuList>
          {menuItems.map(item => (
            <MenuItem key={item.key}>{item.content}</MenuItem>
          ))}
        </MenuList>
      </MenuPopover>
    </Menu>
  );
};

// in COMPONENT_NAME.styles.ts
import { makeStyles, tokens } from '@fluentui/react-components';

export const useStyles = makeStyles({
  actionButton: {
    color: tokens.colorNeutralForeground1,
  },
});

Others

If the MenuPopover is not rendered in the correct position or is displaced due to ref changes, you can manually add the ref. This could be also useful if the Menu instance needs to be reused in different places. Please see the Anchor to Custom Target example in the Menu V9 documentation.

Find more examples here: Sandbox