AniUI

Toggle Group

A group of toggle items where only one can be active at a time, perfect for selection controls like text alignment.

import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";

export function MyScreen() {
  const [value, setValue] = React.useState("center");
  return (
    <ToggleGroup value={value} onValueChange={setValue}>
      <ToggleGroupItem value="left">Left</ToggleGroupItem>
      <ToggleGroupItem value="center">Center</ToggleGroupItem>
      <ToggleGroupItem value="right">Right</ToggleGroupItem>
    </ToggleGroup>
  );
}

Installation

npx @aniui/cli add toggle-group

Usage

app/index.tsx
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";

export function MyScreen() {
  const [value, setValue] = React.useState("center");
  return (
    <ToggleGroup value={value} onValueChange={setValue}>
      <ToggleGroupItem value="left">Left</ToggleGroupItem>
      <ToggleGroupItem value="center">Center</ToggleGroupItem>
      <ToggleGroupItem value="right">Right</ToggleGroupItem>
    </ToggleGroup>
  );
}

Examples

<ToggleGroup value={value} onValueChange={setValue}>
  <ToggleGroupItem value="left">Left</ToggleGroupItem>
  <ToggleGroupItem value="center">Center</ToggleGroupItem>
  <ToggleGroupItem value="right">Right</ToggleGroupItem>
</ToggleGroup>

Props

ToggleGroup

PropTypeDefault
value
string
required
onValueChange
(value: string) => void
required
className
string

Also accepts all View props from React Native.

ToggleGroupItem

PropTypeDefault
value
string
required
className
string
children
ReactNode
required

Also accepts all Pressable props from React Native.

Source

components/ui/toggle-group.tsx
import React, { createContext, useContext } from "react";
import { View, Pressable, Text } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const itemVariants = cva(
  "items-center justify-center rounded-md min-h-12 min-w-12",
  {
    variants: {
      variant: {
        default: "bg-transparent",
        outline: "border border-input bg-transparent",
      },
      size: {
        sm: "px-2 py-1.5",
        md: "px-3 py-2",
        lg: "px-4 py-2.5",
      },
    },
    defaultVariants: { variant: "default", size: "md" },
  }
);
type GroupCtx = { value: string; onValueChange: (v: string) => void };
const Ctx = createContext<GroupCtx>({ value: "", onValueChange: () => {} });
export interface ToggleGroupProps
  extends React.ComponentPropsWithoutRef<typeof View>,
    VariantProps<typeof itemVariants> {
  className?: string;
  value: string;
  onValueChange: (value: string) => void;
  children: React.ReactNode;
}
export function ToggleGroup({ value, onValueChange, variant, size, className, children, ...props }: ToggleGroupProps) {
  return (
    <Ctx.Provider value={{ value, onValueChange }}>
      <View className={cn("flex-row gap-1", className)} accessibilityRole="radiogroup" {...props}>
        {children}
      </View>
    </Ctx.Provider>
  );
}
export interface ToggleGroupItemProps extends React.ComponentPropsWithoutRef<typeof Pressable> {
  className?: string;
  value: string;
  children: React.ReactNode;
}
export function ToggleGroupItem({ value, className, children, ...props }: ToggleGroupItemProps) {
  const { value: selected, onValueChange } = useContext(Ctx);
  const active = selected === value;
  return (
    <Pressable
      className={cn(itemVariants({ variant: "default", size: "md" }), active && "bg-accent", className)}
      onPress={() => onValueChange(value)}
      accessibilityRole="radio"
      accessibilityState={{ selected: active }}
      accessible={true}
      {...props}
    >
      {typeof children === "string" ? (
        <Text className={cn("text-sm font-medium", active ? "text-accent-foreground" : "text-muted-foreground")}>
          {children}
        </Text>
      ) : children}
    </Pressable>
  );
}