diff --git a/.changeset/all-paws-exist.md b/.changeset/all-paws-exist.md index 4f989abd86..95e2fe86ca 100644 --- a/.changeset/all-paws-exist.md +++ b/.changeset/all-paws-exist.md @@ -2,4 +2,4 @@ '@backstage/canon': minor --- -**Breaking changes** We are updating our Link component to use React Aria under the hood. To match their API we are updating the `to` prop to `href` to match both internal and expernal routing. We are also updating our variant naming to include all our new font sizes. +**Breaking changes** We are updating our Link component to use React Aria under the hood. To match their API we are updating the `to` prop to `href` to match both internal and external routing. We are also updating our variant naming to include all our new font sizes. diff --git a/packages/canon/src/components/Link/Link.stories.tsx b/packages/canon/src/components/Link/Link.stories.tsx index 1f2ca04b16..76bac019d4 100644 --- a/packages/canon/src/components/Link/Link.stories.tsx +++ b/packages/canon/src/components/Link/Link.stories.tsx @@ -40,7 +40,7 @@ type Story = StoryObj; export const Default: Story = { args: { - href: '#', + href: '/home', children: 'Sign up for Backstage', }, }; diff --git a/packages/canon/src/components/Link/Link.tsx b/packages/canon/src/components/Link/Link.tsx index e72ea49016..5fefdccd42 100644 --- a/packages/canon/src/components/Link/Link.tsx +++ b/packages/canon/src/components/Link/Link.tsx @@ -21,6 +21,28 @@ import { useStyles } from '../../hooks/useStyles'; import type { LinkProps } from './types'; import { useNavigate, useHref } from 'react-router-dom'; +// Helper function to determine if a link is external +function isExternalLink(href?: string): boolean { + if (!href) return false; + + // Check if it's an absolute URL with protocol + if (href.startsWith('http://') || href.startsWith('https://')) { + return true; + } + + // Check if it's a protocol-relative URL + if (href.startsWith('//')) { + return true; + } + + // Check if it's a mailto: or tel: link + if (href.startsWith('mailto:') || href.startsWith('tel:')) { + return true; + } + + return false; +} + /** @public */ export const Link = forwardRef((props, ref) => { const navigate = useNavigate(); @@ -29,6 +51,7 @@ export const Link = forwardRef((props, ref) => { variant = 'body', weight = 'regular', color = 'primary', + href, ...restProps } = props; @@ -38,11 +61,28 @@ export const Link = forwardRef((props, ref) => { color, }); + const isExternal = isExternalLink(href); + + // If it's an external link, render AriaLink without RouterProvider + if (isExternal) { + return ( + + ); + } + + // For internal links, use RouterProvider return (