Kosmesis
Components

Toggle Group

Single- or multiple-selection toggle group, wrapping Morphos's ToggleGroup primitive.

Installation

npx kosmesis add toggle-group
pnpm dlx kosmesis add toggle-group
yarn dlx kosmesis add toggle-group
bunx kosmesis add toggle-group

Install the following dependencies:

npm install @morphos/inputs class-variance-authority
pnpm add @morphos/inputs class-variance-authority
yarn add @morphos/inputs class-variance-authority
bun add @morphos/inputs class-variance-authority

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): toggle.

Copy and paste the following code into your project.

toggle-group.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { ToggleGroup as MorphosToggleGroup, ToggleGroupItem as MorphosToggleGroupItem, type ToggleGroupItemProps as MorphosToggleGroupItemProps  } from "@morphos/inputs";import { toggleVariants } from "./toggle";import type { VariantProps } from "class-variance-authority";import { cn } from "@/lib/utils";/** * Extends (not wraps) Morphos's `ToggleGroup` so `new ToggleGroup({ type: "single" })` still * yields a real instance with `.isPressed()`/`.toggle()` — what `ToggleGroupItem` needs via its * `group` prop. */@Component()export class ToggleGroup extends MorphosToggleGroup {  render() {    return (      <div        id={this.id}        role="group"        class={cn("flex w-fit items-center gap-1 rounded-md", this.class)}        aria-label={this["aria-label"]}        aria-labelledby={this["aria-labelledby"]}        aria-disabled={this.disabled ? ("true" as const) : undefined}        data-type={this.type}        data-orientation={this.orientation}        data-disabled={this.disabled ? "" : undefined}      >        {this.children}      </div>    );  }}/** * Unlike shadcn/ui's React version, `variant`/`size` aren't inherited from the group via context * (Morphos/PraxisJS compound components pass explicit props instead) — pass the same `variant` * and `size` to `ToggleGroup` and every `ToggleGroupItem` to keep them visually consistent. */export interface ToggleGroupItemProps extends MorphosToggleGroupItemProps, VariantProps<typeof toggleVariants> {}@Component()export class ToggleGroupItem extends StatelessComponent<ToggleGroupItemProps> {  render() {    const { variant, size, class: cls, ...rest } = this.props;    return <MorphosToggleGroupItem class={cn(toggleVariants({ variant, size }), cls)} {...rest} />;  }}

Install the following dependencies:

npm install @morphos/inputs @praxisjs/css
pnpm add @morphos/inputs @praxisjs/css
yarn add @morphos/inputs @praxisjs/css
bun add @morphos/inputs @praxisjs/css

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): toggle.

Copy and paste the following code into your project.

toggle-group.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { ToggleGroup as MorphosToggleGroup, ToggleGroupItem as MorphosToggleGroupItem, type ToggleGroupItemProps as MorphosToggleGroupItemProps  } from "@morphos/inputs";import { ToggleStyles, type ToggleSize, type ToggleVariant } from "./toggle";class ToggleGroupRootStyles extends Stylesheet {  $root = this.css({ display: "flex", width: "fit-content", alignItems: "center", gap: "0.25rem", borderRadius: "0.375rem" });}/** * Extends (not wraps) Morphos's `ToggleGroup` so `new ToggleGroup({ type: "single" })` still * yields a real instance with `.isPressed()`/`.toggle()` — what `ToggleGroupItem` needs via its * `group` prop. */@Component()export class ToggleGroup extends MorphosToggleGroup {  @Styled(ToggleGroupRootStyles) $s!: ToggleGroupRootStyles;  render() {    return (      <div        id={this.id}        role="group"        class={cx(this.$s.$root, this.class)}        aria-label={this["aria-label"]}        aria-labelledby={this["aria-labelledby"]}        aria-disabled={this.disabled ? ("true" as const) : undefined}        data-type={this.type}        data-orientation={this.orientation}        data-disabled={this.disabled ? "" : undefined}      >        {this.children}      </div>    );  }}/** * Unlike shadcn/ui's React version, `variant`/`size` aren't inherited from the group via context * (Morphos/PraxisJS compound components pass explicit props instead) — pass the same `variant` * and `size` to `ToggleGroup` and every `ToggleGroupItem` to keep them visually consistent. */export interface ToggleGroupItemProps extends MorphosToggleGroupItemProps {  variant?: ToggleVariant;  size?: ToggleSize;}@Component()export class ToggleGroupItem extends StatelessComponent<ToggleGroupItemProps> {  @Styled(ToggleStyles) $s!: ToggleStyles;  render() {    const { variant = "default", size = "default", class: cls, ...rest } = this.props;    const variants: Record<ToggleVariant, string> = { default: this.$s.$variantDefault, outline: this.$s.$variantOutline };    const sizes: Record<ToggleSize, string> = { default: this.$s.$sizeDefault, sm: this.$s.$sizeSm, lg: this.$s.$sizeLg };    return <MorphosToggleGroupItem class={cx(this.$s.$root, variants[variant], sizes[size], cls)} {...rest} />;  }}

Examples

Usage

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

@Component()
class TextAlignPicker extends StatefulComponent {
  @State() group = new ToggleGroup({ type: "single", defaultValue: "left" });

  render() {
    return (
      <ToggleGroup type="single" defaultValue="left" variant="outline">
        <ToggleGroupItem group={this.group} value="left" variant="outline">Left</ToggleGroupItem>
        <ToggleGroupItem group={this.group} value="center" variant="outline">Center</ToggleGroupItem>
        <ToggleGroupItem group={this.group} value="right" variant="outline">Right</ToggleGroupItem>
      </ToggleGroup>
    );
  }
}

Unlike shadcn/ui's React version, variant/size aren't inherited from the group via context — pass the same variant/size to ToggleGroup and every ToggleGroupItem to keep them visually consistent.

Props

ToggleGroup

PropTypeDefault
type"single" | "multiple"— required
valuestring | string[]
defaultValuestring | string[]
disabledbooleanfalse
orientation"horizontal" | "vertical""horizontal"
onValueChange(value: string | string[]) => void
aria-labelstring
aria-labelledbystring

ToggleGroup itself does not accept variant/size — despite the Usage example above passing variant="outline" to it, that prop has no effect on the group; only ToggleGroupItem renders variant/size styling, so it must be set per-item.

ToggleGroupItem

PropTypeDefault
groupToggleGroup— required
valuestring— required
disabledboolean
variant"default" | "outline""default"
size"default" | "sm" | "lg""default"

On this page