Created
April 25, 2023 18:53
-
-
Save jasikpark/739f528ec4e3a8e8e5e05b5617333dc4 to your computer and use it in GitHub Desktop.
Example of a polymorphic ariakit Tab component that can be a button or link
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Tab as AriakitTab, type TabProps } from 'ariakit/tab'; | |
import cn from 'classnames'; | |
import { useLayoutEffect, useRef } from 'react'; | |
import { useRect } from '@hooks/useRect'; | |
import { useAnimatedTabs } from '../context/useAnimatedTabs'; | |
import styles from './Tab.module.css'; | |
/** | |
* A tab that goes at the top of a tab panel, which a user clicks on to change the UI underneath. | |
* This is a button by default, but can also be a react-router Link, if the `to` and `as` props are provided. | |
*/ | |
export function Tab<T extends 'button' | 'a' = 'button'>({ as, ...props }: TabProps<T>) { | |
// get the state and style changing function from context | |
const { state, setActiveRect } = useAnimatedTabs(); | |
// measure the size of our element, only listen to rect if active | |
const ref = useRef<HTMLButtonElement & HTMLAnchorElement>(null); | |
// @ts-expect-error Unsure how to type-narrow this depending on the value of `as` | |
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | |
const isSelected = state.selectedId === ref.current?.id || ref.current?.href?.includes(state.selectedId); | |
const rect = useRect(ref, { observe: isSelected }); | |
// callup to set styles whenever we're active | |
useLayoutEffect(() => { | |
if (isSelected) { | |
setActiveRect(rect); | |
} | |
}, [isSelected, rect, setActiveRect]); | |
return ( | |
// @ts-expect-error generics are hard. | |
<AriakitTab ref={ref} as={as} className={cn(styles.Tab, { [styles.Tab___isActive]: isSelected })} {...props} /> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment