Radio
tetra-ui/radioFreeComponent
A control that indicates a selected option within a group.
Live preview
live · rendered by the registry
Rendered by tetra-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://tetra-ui.com/r/radio.jsonSource
1import { useEffect } from "react";2import type { View as ViewType } from "react-native";3import Animated, {4 interpolateColor,5 useAnimatedStyle,6 useSharedValue,7 withSequence,8 withTiming,9} from "react-native-reanimated";10import { useCSSVariable } from "uniwind";11import { cn } from "../lib/utils";1213// Constants14const ANIMATION_DURATION = 180;15const DOT_APPEAR_DURATION = 120;16const DOT_CONTRACT_DURATION = 100;17const DOT_CONTRACT_SCALE = 0.75;1819// Types20export type RadioProps = Omit<21 React.ComponentProps<typeof ViewType>,22 "children"23> & {24 checked?: boolean;25 invalid?: boolean;26};2728// Components29export const Radio = ({30 className,31 checked,32 invalid,33 ...props34}: RadioProps) => {35 const [primaryColor, primaryForegroundColor] = useCSSVariable([36 "--color-primary",37 "--color-primary-foreground",38 ]) as [string, string];3940 const checkedSharedValue = useSharedValue(checked ? 1 : 0);41 const dotScale = useSharedValue(checked ? DOT_CONTRACT_SCALE : 0);4243 useEffect(() => {44 if (checked) {45 checkedSharedValue.value = withTiming(1, {46 duration: ANIMATION_DURATION,47 });48 dotScale.value = withSequence(49 withTiming(1, { duration: DOT_APPEAR_DURATION }),50 withTiming(DOT_CONTRACT_SCALE, { duration: DOT_CONTRACT_DURATION })51 );52 return;53 }5455 checkedSharedValue.value = 0;56 dotScale.value = 0;57 }, [checked, checkedSharedValue, dotScale]);5859 const animatedStyle = useAnimatedStyle(() => {60 const backgroundColor = interpolateColor(61 checkedSharedValue.value,62 [0, 1],63 ["transparent", primaryColor]64 );6566 return {67 backgroundColor,68 };69 });7071 const dotAnimatedStyle = useAnimatedStyle(() => ({72 opacity: dotScale.value > 0 ? 1 : 0,73 transform: [{ scale: dotScale.value }],74 }));7576 return (77 <Animated.View78 {...props}79 accessibilityState={{ checked }}80 className={cn(81 "size-6 shrink-0 items-center justify-center rounded-full border border-input shadow-xs dark:bg-input/30",82 checked && "border-primary",83 invalid && "border-destructive",84 className85 )}86 style={animatedStyle}87 >88 <Animated.View89 className="size-2.5 rounded-full"90 style={[{ backgroundColor: primaryForegroundColor }, dotAnimatedStyle]}91 />92 </Animated.View>93 );94};
What it pulls in
npm packages
Files it writes
More from tetra-ui
All 41 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | tetra-ui | Components | Free | 1 dep | |
| Action Inputaction-input | tetra-ui | Components | Free | no deps | |
| Alertalert | tetra-ui | Components | Free | no deps | |
| Avataravatar | tetra-ui | Components | Free | no deps | |
| Badgebadge | tetra-ui | Components | Free | no deps | |
| Bottom Sheetbottom-sheet | tetra-ui | Components | Free | 4 deps · 7 files | |
| Buttonbutton | tetra-ui | Components | Free | no deps | |
| Cardcard | tetra-ui | Components | Free | no deps |
