# Migration of components using IButtonProps **See https://hackmd.io/836e7v9oReGWP6I_Y7CVXg for original discussion.** Using SpinButton as an example here. It's relatively clean, but in other cases if the actual use of button is inside a sub-component (like in ContextualMenu) it will be messier. The basic idea is: - **Leave SpinButton in `@fluentui/react` to avoid circular dependencies** - Update the prop types to accept new ButtonProps by default - Add compat prop types which use the old IButtonProps - In SpinButtonBase, use the new button by default, but add essentially an internal slot prop for overriding which button to use - Add a compat SpinButton file which uses the compat props and passes through the old IconButton to the button slot ## Details In `SpinButton.types.ts`, update to use the new `ButtonProps`: ```ts import { ButtonProps } from '@fluentui/react-button'; export interface ISpinButtonProps /*...*/ { iconButtonProps?: IButtonProps; } // This is mainly a hack to ensure links work on the doc site /** * {@docCategory SpinButton} */ export type INewSpinButtonProps = ISpinButtonProps; ``` In new `CompatSpinButton.types.ts` (may not use that exact filename), export props which switch back to the old `IButtonProps`: ```ts import { IButtonProps } from '../../compat/Button'; import { INewSpinButtonProps } from './SpinButton.types'; export interface ISpinButtonProps extends Omit<INewSpinButtonProps, 'iconButtonProps'> { iconButtonProps?: IButtonProps; // switch type back to old version } ``` In `SpinButton.base.tsx`, use the new button by default but add (essentially) a slot for passing the compat one through. (Do NOT directly reference the old Button to avoid bundle size issues!) ```tsx import { Button } from '@fluentui/react-button'; export interface ISpinButtonInternalProps extends ISpinButtonProps { buttonComponent?: React.ComponentType; } export const SpinButtonBase: React.FunctionComponent<ISpinButtonInternalProps> = props => { // Update references to button as follows: const { buttonComponent: ButtonComponent = Button, iconButtonProps } = props; <ButtonComponent {...(iconButtonProps as any)}> } ``` In new `CompatSpinButton.tsx` (may not use that exact filename), use the slot to pass in the old button: ```tsx import { ISpinButtonInternalProps, SpinButtonBase } from './SpinButton.base'; import { ISpinButtonProps } from './CompatSpinButton.types'; import { IconButton } from '../../compat/Button'; export const SpinButton: React.FunctionComponent<ISpinButtonProps> = styled<ISpinButtonProps, {}, ISpinButtonStyles>( SpinButtonBase, getStyles, () => { const internalProps: Partial<ISpinButtonInternalProps> = { buttonComponent: IconButton }; // Use a cast so we don't expose the internal props in the public typings return internalProps as any; }, { scope: 'SpinButton', }, ); ```