AniUI

Toggle Group

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

Web preview — components render natively on iOS & Android
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#

Web preview — components render natively on iOS & Android
<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.

Accessibility#

  • Group of toggle buttons with single or multiple selection.
  • Each toggle item has accessibilityRole="button" with selected state.

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>
  );
}