T
TanStack2mo ago
conscious-sapphire

React-aria-components & createLink

heya, I'm working with RAC and tanstack router, and have moved away from RAC's RouterProvider pattern to createLink, but a few things have come up. ListBoxItem can potentially be a link, but not always, if passed a href prop it renders an 'a' tag, otherwise its a div. However, if I wrap my styled version of ListBoxItem in createLink it's always a 'a', and the to prop is always required.

export function ListBoxItem(props: ListBoxItemProps) { // can render 'a' or 'div'
const textValue =
props.textValue ||
(typeof props.children === "string" ? props.children : undefined);
return (
<AriaListBoxItem {...props} textValue={textValue} className={itemStyles}>
{composeRenderProps(props.children, (children) => (
<>
{children}
<div className="absolute left-4 right-4 bottom-0 h-px bg-white/20 forced-colors:bg-[HighlightText] hidden [.group[data-selected]:has(+[data-selected])_&]:block" />
</>
))}
</AriaListBoxItem>
);
}
export const ListBoxItemLink = createLink(ListBoxItem); // will always render 'a'

export function ListBoxItem(props: ListBoxItemProps) { // can render 'a' or 'div'
const textValue =
props.textValue ||
(typeof props.children === "string" ? props.children : undefined);
return (
<AriaListBoxItem {...props} textValue={textValue} className={itemStyles}>
{composeRenderProps(props.children, (children) => (
<>
{children}
<div className="absolute left-4 right-4 bottom-0 h-px bg-white/20 forced-colors:bg-[HighlightText] hidden [.group[data-selected]:has(+[data-selected])_&]:block" />
</>
))}
</AriaListBoxItem>
);
}
export const ListBoxItemLink = createLink(ListBoxItem); // will always render 'a'
And with Link,

function StyledLink(props: Props) {
return (
<AriaLink
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
styles({ ...renderProps, className, variant: props.variant }),
)}
/>
);
}

export const Link = createLink(StyledLink);

function StyledLink(props: Props) {
return (
<AriaLink
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
styles({ ...renderProps, className, variant: props.variant }),
)}
/>
);
}

export const Link = createLink(StyledLink);
I originally only exported the 'Link' component from my styled implementation, but in one place I needed to link externally via a href but typescript marks to a required prop which doesn't support external links. I know the answer is 'you created a link, obviously it's gonna be a link' and just have 2 components, one for internal links, one for external links / standard behaviours is fair, but maybe someone has a better idea? Thanks!
2 Replies
rare-sapphire
rare-sapphire2mo ago
we wanted to allow href instead of to on link just have not done yet
conscious-sapphire
conscious-sapphireOP2mo ago
That'd be great, having 1 Link, and then ListBoxItem & ListBoxItemLink is also cool since I won't have to think of new ways of naming things, and seems more intentional. Thanks for all your hard work!

Did you find this page helpful?