@wikicasa-dev/components · Selection · primitive

RadioGroupItemPrimitive

Unstyled radio option (reka-ui RadioGroupItem) for custom segmented buttons or cards inside RadioButtonGroup.

Unstyled radio option (reka-ui RadioGroupItem) for custom segmented buttons or cards inside RadioButtonGroup.

import RadioGroupItemPrimitive from "@wikicasa-dev/components/UIKit/Radio/v2/RadioGroupItemPrimitive";

An option with no visuals of its own: an unstyled <button role="radio"> whose content is your slot. Use it inside RadioButtonGroup when options should look like segmented tabs, pills or selectable cards (e.g. "Vendita | Affitto | Asta" tabs, condition buttons in a filter modal). For the classic circle-and-label look use RadioButtonItem.

The default slot receives { checked, required, disabled }. select is emitted when the option is chosen.

Usage

<script setup lang="ts">
import { ref } from "vue";
import RadioButtonGroup from "@wikicasa-dev/components/UIKit/Radio/v2/RadioButtonGroup";
import RadioGroupItemPrimitive from "@wikicasa-dev/components/UIKit/Radio/v2/RadioGroupItemPrimitive";

const contract = ref("vendita");
const options = [
  { value: "vendita", label: "Vendita" },
  { value: "affitto", label: "Affitto" },
  { value: "asta", label: "Asta" },
];
</script>

<template>
  <RadioButtonGroup v-model="contract" aria-label="Tipo di contratto" orientation="horizontal" class="segmented">
    <RadioGroupItemPrimitive v-for="o in options" :key="o.value" :value="o.value" :data-cy="`contract-${o.value}`" class="segment">
      {{ o.label }}
    </RadioGroupItemPrimitive>
  </RadioButtonGroup>
</template>

<style scoped>
.segmented { display: grid; grid-template-columns: repeat(3, 1fr); }
.segment { padding: 6px 20px; border: 0; border-bottom: 2px solid transparent; background: transparent; }
.segment[data-state="checked"] { border-bottom-color: rgb(var(--uikit-color-w-primary)); font-weight: 600; }
.segment:focus-visible { outline: 2px solid rgb(var(--uikit-color-w-primary)); }
</style>

Do / Don't

  • Do always place it inside RadioButtonGroup (the library has no separate radio root primitive) and give it a unique value.
  • Do put readable text in the slot; icon-only options need an aria-label.
  • Do style checked and disabled looks with [data-state="checked"] and [data-disabled], and keep a visible :focus-visible style.
  • Don't use it when the classic radio look is fine; use RadioButtonItem.

Styling hooks

None: it is an unstyled <button>; class goes on it. Use data-state / data-disabled selectors and the design tokens.

API

Generated from the component's types. Do not edit by hand.

Props

Name Type Default Required Description
dataCy string
disabled boolean When true, prevents the user from interacting with the radio item.
asChild boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details.
as AsTag | Component The element or component this component should render as. Can be overwritten by asChild.
required boolean When true, indicates that the user must set the value before the owning form can be submitted.
value AcceptableValue The value given as data when submitted with a name.
id string
name string The name of the field. Submitted with its owning form as part of a name/value pair.

Events

Name Payload
select [SelectEvent$2]

v-model

None.

Slots

Name Slot props
default { checked: boolean; required: boolean; disabled: boolean; }

Exposed (template ref)

None.