Use unstyled link for LinkButton

Signed-off-by: James Brooks <jamesbrooks@spotify.com>
This commit is contained in:
James Brooks
2026-01-19 23:29:30 +00:00
parent 0aaaf7b00e
commit cebfea769a
4 changed files with 30 additions and 16 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Removed link styles from LinkButton to avoid styling inconsistencies related to import order.
@@ -180,11 +180,11 @@ const getNodeText = (node: ReactNode): string => {
};
/**
* Thin wrapper on top of material-ui's Link component, which...
* - Makes the Link use react-router
* - Captures Link clicks as analytics events.
* Unstyled link primitive which...
* - Uses react-router for internal links.
* - Captures link clicks as analytics events.
*/
export const Link = forwardRef<any, LinkProps>(
export const UnstyledLink = forwardRef<any, LinkProps>(
({ onClick, noTrack, externalLinkIcon, ...props }, ref) => {
const classes = useStyles();
const analytics = useAnalytics();
@@ -213,7 +213,7 @@ export const Link = forwardRef<any, LinkProps>(
return external ? (
// External links
<MaterialLink
<a
{...(newWindow ? { target: '_blank', rel: 'noopener' } : {})}
{...props}
{...(props['aria-label']
@@ -229,16 +229,17 @@ export const Link = forwardRef<any, LinkProps>(
<Typography component="span" className={classes.visuallyHidden}>
, Opens in a new window
</Typography>
</MaterialLink>
</a>
) : (
// Interact with React Router for internal links
<MaterialLink
{...props}
ref={ref}
component={RouterLink}
to={to}
onClick={handleClick}
/>
<RouterLink {...props} ref={ref} to={to} onClick={handleClick} />
);
},
) as (props: LinkProps) => JSX.Element;
);
/**
* Thin wrapper combining UnstyledLink with material-ui's Link component.
*/
export const Link = forwardRef<any, LinkProps>((props, ref) => {
return <MaterialLink {...props} ref={ref} component={UnstyledLink} />;
}) as (props: LinkProps) => JSX.Element;
@@ -38,4 +38,12 @@ describe('<LinkButton />', () => {
});
expect(screen.getByText(testString)).toBeInTheDocument();
});
it('should not have MuiLink class names', async () => {
await renderInTestApp(<LinkButton to="/test">Navigate!</LinkButton>);
const button = await screen.findByRole('button', { name: 'Navigate!' });
expect(button).toHaveClass(/MuiButton/);
expect(button).not.toHaveClass(/MuiLink/);
});
});
@@ -18,7 +18,7 @@ import MaterialButton, {
ButtonProps as MaterialButtonProps,
} from '@material-ui/core/Button';
import { forwardRef } from 'react';
import { Link, LinkProps } from '../Link';
import { UnstyledLink, LinkProps } from '../Link/Link';
/**
* Properties for {@link LinkButton}
@@ -35,7 +35,7 @@ export type LinkButtonProps = MaterialButtonProps &
* This wrapper is here to reset the color of the Link and make typescript happy.
*/
const LinkWrapper = forwardRef<any, LinkProps>((props, ref) => (
<Link ref={ref} {...props} color="initial" />
<UnstyledLink ref={ref} {...props} color="initial" />
));
/**