Select
Displays a list of options for the user to pick from.
Installation
bash npx @moe/cli add select Install the following dependency:
npx expo install @rn-primitives/selectCopy/paste the following code to @/components/ui/select.tsx
import * as SelectPrimitive from "@rn-primitives/select";
import * as React from "react";
import { Platform, StyleSheet, View } from "react-native";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import { Check } from "@/lib/icons/Check";
import { ChevronDown } from "@/lib/icons/ChevronDown";
import { ChevronUp } from "@/lib/icons/ChevronUp";
import { cn } from "@/lib/utils";
type Option = SelectPrimitive.Option;
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-row h-10 native:h-12 items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm text-muted-foreground web:ring-offset-background web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 [&>span]:line-clamp-1",
props.disabled && "web:cursor-not-allowed opacity-50",
className,
)}
{...props}
>
<>{children}</>
<ChevronDown size={16} aria-hidden className="text-foreground opacity-50" />
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>) => {
return (
<SelectPrimitive.ScrollUpButton
className={cn(
"flex items-center justify-center py-1 web:cursor-default",
className,
)}
{...props}
>
<ChevronUp size={14} className="text-foreground" />
</SelectPrimitive.ScrollUpButton>
);
};
const SelectScrollDownButton = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>) => {
return (
<SelectPrimitive.ScrollDownButton
className={cn(
"flex items-center justify-center py-1 web:cursor-default",
className,
)}
{...props}
>
<ChevronDown size={14} className="text-foreground" />
</SelectPrimitive.ScrollDownButton>
);
};
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => {
return (
<SelectPrimitive.Portal>
<SelectPrimitive.Overlay
style={Platform.OS !== "web" ? StyleSheet.absoluteFill : undefined}
>
<Animated.View entering={FadeIn} exiting={FadeOut}>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover shadow-md shadow-foreground/5",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</Animated.View>
</SelectPrimitive.Overlay>
</SelectPrimitive.Portal>
);
});
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn(
"py-1.5 native:pb-2 pl-8 native:pl-10 pr-2 text-sm native:text-base font-semibold text-popover-foreground",
className,
)}
{...props}
/>
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex flex-row w-full web:cursor-default web:select-none items-center rounded-sm py-1.5 native:py-2 pl-8 native:pl-10 pr-2 web:outline-none web:focus:bg-accent active:bg-accent web:hover:bg-accent",
props.disabled && "web:pointer-events-none opacity-50",
className,
)}
{...props}
>
<View className="absolute left-2 native:left-3.5 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check size={16} strokeWidth={3} className="text-popover-foreground" />
</SelectPrimitive.ItemIndicator>
</View>
<SelectPrimitive.ItemText className="text-sm native:text-lg text-popover-foreground native:text-base web:group-focus:text-accent-foreground" />
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectScrollDownButton,
SelectScrollUpButton,
SelectSeparator,
SelectTrigger,
SelectValue,
type Option,
};Usage
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | The controlled value |
onValueChange | (value: string) => void | - | Event handler called when value changes |