Skip to Content
GuideCustomizationComponent Overrides

Component Overrides

Fusion is designed with flexibility in mind, allowing you to tailor core components to your project’s specific needs without ejecting or modifying the library’s source code. This is primarily achieved through the ComponentProvider and the useComponents hook.

The ComponentProvider

The ComponentProvider is a React Context provider that allows you to supply alternative implementations for any of the standard fusion-ui components.

When a Fusion component (or another component that uses useComponents) needs to render a sub-component (e.g., an Input inside a FormField), it fetches its implementation from the ComponentProvider. If no implementation is found, the default fusion-ui implementation is rendered.

When to Override

There are two reasons why you might want to use the ComponentProvider.

  • Custom Layout: If you need a Button that looks significantly different from the default fusion-ui Button across your entire application and cannot achieve that with just tokens alone.
  • Custom Logic: Embedding additional analytics, accessibility enhancements, or specific business logic into a standard component.

How to Override

Create Your Component

Your custom implementation needs to be type-compatible with Fusion’s implementation. This means it needs to support at least the same props as the original and forward the ref to the underlying DOM element.

src/components/MyButton.tsx
import { ButtonProps } from "@codedazur/fusion-ui"; import { forwardRef } from "react"; import { button } from "./MyButton.css"; export const MyButton = forwardRef<HTMLButtonElement, ButtonProps>( ({ variant = "primary", size = "medium", children, ...props }, ref) => { return ( <button ref={ref} className={button({ variant, size })} {...props}> {children} </button> ); }, );

Although your component’s type must be compatible, you can of course choose to ignore some of the original props, and you can also extend them with additional, optional props, though those will not be used by Fusion itself.

Provide Your Component

Pass a components prop to ComponentProvider. This prop is an object where keys are the names of the fusion-ui components you want to override (as strings, e.g., “Button”, “Card”) and values are your custom component implementations.

import { App, ComponentProvider } from "@codedazur/fusion-ui"; import { MyButton } from "../components/MyButton"; import { lightTheme } from "@codedazur/fusion-ui/style"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body> <ComponentProvider components={{ Button: MyButton, }} > <App theme={lightTheme}>{children}</App> </ComponentProvider> </body> </html> ); }
Note

Both @codedazur/fusion-sanity and @codedazur/fusion-ui export a ComponentProvider component. You can use either one, but only the one from @codedazur/fusion-sanity will allow you to override components that are specific to the Sanity integration.

Now, any component that fetches the Button from the component context within this provider’s scope will render a MyButton instead of the default Button.

The useComponents Hook

The useComponents hook fetches component implementations from the ComponentContext. When you build custom components that need to respect these potential overrides (especially if they are meant to be part of your own reusable component library within the project), you should use useComponents.

const { Foo, Bar } = useComponents();

It returns an object where the keys are the component names and the values are the actual component implementations to render. By default, the standard Fusion components are returned, but you can use the ComponentProvider to override them.

Imagine you’re building a UserCard for generic use and you want it to support customization of its elements. Instead of directly importing Button, Text, and Surface from @codedazur/fusion-ui, you can use the useComponents hook to get them.

import { useComponents } from "@codedazur/fusion-ui"; export interface UserCardProps { name: string; bio: string; onSendMessage: () => void; } export function UserCard({ name, onSendMessage }: UserCardProps) { const { Button, Text, Surface } = useComponents(); return ( <Surface padding={400} border={{ radius: 200 }} constraints={{ maxWidth: 600 }} flex={{ direction: "column", gap: 300 }} > <Text variant="headline" size="medium"> {name} </Text> <Text variant="body" size="small"> {bio} </Text> <Button variant="primary" size="small" onClick={onSendMessage}> Send Message </Button> </Surface> ); }

By leveraging the useComponents hook, your UserCard ensures that if Surface, Button, or Text are overridden higher up in the tree via a ComponentProvider, those custom versions will be used instead of the standard implementations.

Last updated on