> ## Content Index
> Fetch the complete content index at: https://madewithlove.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Learning from OSS: configuring your Link component via a Provider (Braid)
- URL: https://madewithlove.com/blog/learning-from-oss-configuring-your-link-component-via-a-provider-braid/
- Published: 2025-08-07T08:14:21.000Z
- Updated: 2026-05-19T07:33:24.000Z
- Description: Learn how SEEK’s Braid Design System uses a linkComponent provider to flexibly support routing across React apps. A great pattern for design systems, and one madewithlove engineers keep coming back to when building scalable front-end libraries.
- Author: Geoffrey Dhuyvetters
- Tags: Engineering, Tutorials, React, Frontend, Open source

Open-source software provides a great learning opportunity, and in this series, I’ll explore solutions to specific problems I’ve encountered while working with code and documentation from open-source projects.

Today, let’s take a look at the linkComponent property in the [Braid Design System](https://seek-oss.github.io/braid-design-system/) by SEEK.

## The challenge of handling links in different applications​

When building a component library, it needs to be flexible enough to work across different applications, each of which might have its own way of handling links.

\- [Link](https://reactrouter.com/en/main/components/link#link%C2%A0) in react-router  
\- Next.js [Link](https://nextjs.org/docs/pages/api-reference/components/link) component  
\- an [anchor tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)  
  
It wouldn’t be scalable or efficient to manage multiple [Link component](https://madewithlove.com/blog/learning-from-oss-legacybehaviour-property-on-next-js-s-link-component/)s for every possible routing solution. Instead, SEEK came up with an elegant solution.

## Seeks solution using React context

Instead of creating different Link components for each use case, [SEEK](https://www.seek.com.au/)'s team came up with an elegant solution: they added a [linkComponent property on their BraidProvider](https://seek-oss.github.io/braid-design-system/components/BraidProvider#providing-a-custom-link-component). This approach allows developers to specify a single Link component that works seamlessly across different routing implementations. Whether it’s React Router, Next.js, or an anchor tag, the linkComponent ensures that the appropriate link behavior is consistently applied throughout the application, without duplicating the code or logic for each specific case.  

```javascript
import React from "react"
import { Link as ReactRouterLink } from "react-router-dom"
import { BraidProvider, makeLinkComponent } from "braid-design-system"

// internal links via ReactRouterLink
// external via anchor tag

const CustomLink = makeLinkComponent(({ href, ...restProps }, ref) =>
  href[0] === "/" ? (
    <ReactRouterLink ref={ref} to={href} {...restProps} />
  ) : (
    <a ref={ref} href={href} {...restProps} />
  )
)

export const App = () => (
  <BraidProvider linkComponent={CustomLink}>
    // ...
  </BraidProvider>
)
```

Let's take a look at the implementation, which is fairly straightforward. First, they set up context and provided a sensible default (anchor tag)

```javascript
export interface LinkComponentProps
  extends AnchorHTMLAttributes<HTMLAnchorElement> {
  href: string;
}

export type LinkComponent =
  | ReturnType<typeof makeLinkComponent>
  | ComponentType<LinkComponentProps>;

const DefaultLinkComponent = (props) => (
  <a {...props} />
)

const LinkComponentContext = createContext<LinkComponent>(DefaultLinkComponent);
```

They created and exported a useLinkComponent hook that returns the value in context.

```javascript
export const useLinkComponent = (ref: Ref<HTMLAnchorElement>) => {
  const linkComponent = useContext(LinkComponentContext);

  // assert + ref check removed here

  return linkComponent;
};
```

Lastly, the BraidProvider receives a linkComponent and passes it down (if set) to the context.

```javascript
export interface BraidProviderProps {
  linkComponent?: LinkComponent;
  children: ReactNode;
}

export const BraidProvider = ({
  linkComponent,
  children,
}: BraidProviderProps) => {

  const linkComponentFromContext = useContext(LinkComponentContext);

    // other Providers + props being passed down

  return (
    <LinkComponentContext.Provider
      value={linkComponent || linkComponentFromContext}
    >
      {children}
    </LinkComponentContext.Provider>
  );
};
```

Whenever a component needs to retrieve the configured Link component, it uses the useLinkComponent hook.

Link / [source](https://github.com/seek-oss/braid-design-system/blob/master/packages/braid-design-system/src/lib/components/Link/Link.tsx)

```javascript
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
  ({ href, className, ...restProps }, ref) => {
    const LinkComponent = useLinkComponent(ref);

    return (
      <LinkComponent
        ref={ref}
        href={href}
        className={clsx(atoms({ reset: 'a' }), className)}
        {...restProps}
      />
    );
  },
);
```

ButtonLink / [source](https://github.com/seek-oss/braid-design-system/blob/master/packages/braid-design-system/src/lib/components/ButtonLink/ButtonLink.tsx)

```javascript
<ButtonContainer bleed={bleed} variant={variant}>
    <Box
      component={LinkComponent}
      ref={ref}
      {...restProps}
      {...buildDataAttributes({ data, validateRestProps: false })}
      {...useButtonStyles({
        variant,
        tone,
        size,
        bleed: bleed || bleedY,
        loading,
      })}
    >
      <ButtonOverlays variant={variant} tone={tone} />
      <ButtonText
        variant={variant}
        tone={tone}
        size={size}
        loading={loading}
        icon={icon}
        iconPosition={iconPosition}
        bleed={bleed}
      >
        {children}
      </ButtonText>
    </Box>
</ButtonContainer>
```

I've implemented this pattern several times in custom pattern libraries. Credit where credit is due.