Radio Button Group
Allows single selection from multiple options.
Usage
solid
outline
import { RadioButtonGroup } from '~/components/ui'
export const Demo = (props: RadioButtonGroup.RootProps) => {
const options = [{ value: 'S' }, { value: 'M' }, { value: 'L' }, { value: 'XL' }]
return (
<RadioButtonGroup.Root defaultValue="M" {...props}>
{options.map((option, id) => (
<RadioButtonGroup.Item key={id} value={option.value} disabled={option.value === 'L'} px="0">
<RadioButtonGroup.ItemControl />
<RadioButtonGroup.ItemText>{option.value}</RadioButtonGroup.ItemText>
<RadioButtonGroup.ItemHiddenInput />
</RadioButtonGroup.Item>
))}
</RadioButtonGroup.Root>
)
}
Installation
npx @park-ui/cli components add radio-button-group
1
Styled Primitive
Copy the code snippet below into ~/components/ui/primitives/radio-button-group.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { RadioGroup } from '@ark-ui/react/radio-group'
import { type RadioButtonGroupVariantProps, radioButtonGroup } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(radioButtonGroup)
export interface RootProps
extends Assign<HTMLStyledProps<'div'>, RadioGroup.RootProps>,
RadioButtonGroupVariantProps {}
export const Root = withProvider<HTMLDivElement, RootProps>(RadioGroup.Root, 'root')
export const Indicator = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, RadioGroup.IndicatorProps>
>(RadioGroup.Indicator, 'indicator')
export const ItemControl = withContext<
HTMLDivElement,
Assign<HTMLStyledProps<'div'>, RadioGroup.ItemControlProps>
>(RadioGroup.ItemControl, 'itemControl')
export const Item = withContext<
HTMLLabelElement,
Assign<HTMLStyledProps<'label'>, RadioGroup.ItemProps>
>(RadioGroup.Item, 'item')
export const ItemText = withContext<
HTMLSpanElement,
Assign<HTMLStyledProps<'span'>, RadioGroup.ItemTextProps>
>(RadioGroup.ItemText, 'itemText')
export const Label = withContext<
HTMLLabelElement,
Assign<HTMLStyledProps<'label'>, RadioGroup.LabelProps>
>(RadioGroup.Label, 'label')
export {
RadioGroupContext as Context,
RadioGroupItemHiddenInput as ItemHiddenInput,
} from '@ark-ui/react/radio-group'
import { type Assign, RadioGroup } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type RadioGroupVariantProps, radioButtonGroup } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(radioButtonGroup)
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
Assign<Assign<HTMLStyledProps<'div'>, RadioGroup.RootProps>, RadioGroupVariantProps>
>(RadioGroup.Root, 'root')
export const Indicator = withContext<Assign<HTMLStyledProps<'div'>, RadioGroup.IndicatorProps>>(
RadioGroup.Indicator,
'indicator',
)
export const ItemControl = withContext<Assign<HTMLStyledProps<'div'>, RadioGroup.ItemControlProps>>(
RadioGroup.ItemControl,
'itemControl',
)
export const Item = withContext<Assign<HTMLStyledProps<'label'>, RadioGroup.ItemProps>>(
RadioGroup.Item,
'item',
)
export const ItemText = withContext<Assign<HTMLStyledProps<'span'>, RadioGroup.ItemTextProps>>(
RadioGroup.ItemText,
'itemText',
)
export const Label = withContext<Assign<HTMLStyledProps<'label'>, RadioGroup.LabelProps>>(
RadioGroup.Label,
'label',
)
export {
RadioGroupContext as Context,
RadioGroupItemHiddenInput as ItemHiddenInput,
} from '@ark-ui/solid'
No snippet found
Extend ~/components/ui/primitives/index.ts
with the following line:
export * as RadioButtonGroup from './radio-button-group'
2
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { radioGroupAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const radioButtonGroup = defineSlotRecipe({
className: 'radioButtonGroup',
slots: radioGroupAnatomy.keys(),
base: {
root: {
colorPalette: 'accent',
display: 'flex',
flexWrap: 'wrap',
},
item: {
alignItems: 'center',
appearance: 'none',
borderColor: 'border.default',
borderRadius: 'l2',
borderWidth: '1px',
color: 'fg.default',
cursor: 'pointer',
display: 'inline-flex',
fontWeight: 'semibold',
justifyContent: 'center',
outline: 'none',
position: 'relative',
transitionDuration: 'normal',
transitionProperty: 'background, border-color, color, box-shadow',
transitionTimingFunction: 'default',
userSelect: 'none',
verticalAlign: 'middle',
whiteSpace: 'nowrap',
_hover: {
background: 'gray.a2',
},
_checked: {
cursor: 'default',
},
_disabled: {
borderColor: 'border.disabled',
color: 'fg.disabled',
cursor: 'not-allowed',
_hover: {
background: 'initial',
borderColor: 'border.disabled',
color: 'fg.disabled',
},
},
},
itemText: {
display: 'inline-flex',
alignItems: 'center',
},
},
defaultVariants: {
size: 'md',
variant: 'solid',
},
variants: {
variant: {
solid: {
item: {
_checked: {
background: 'colorPalette.default',
borderColor: 'colorPalette.default',
color: 'colorPalette.fg',
_hover: {
color: 'colorPalette.fg',
background: 'colorPalette.default',
},
},
},
},
outline: {
item: {
_checked: {
borderColor: 'colorPalette.default',
boxShadow: '0 0 0 1px var(--colors-color-palette-default)',
_hover: {
background: 'initial',
},
},
},
},
},
size: {
sm: {
root: {
gap: '2',
},
item: {
h: '9',
minW: '9',
textStyle: 'sm',
px: '3.5',
'& svg': {
width: '4.5',
height: '4.5',
},
},
itemText: {
gap: '2',
},
},
md: {
root: {
gap: '3',
},
item: {
h: '10',
minW: '10',
textStyle: 'sm',
px: '4',
'& svg': {
width: '5',
height: '5',
},
},
itemText: {
gap: '2',
},
},
lg: {
root: {
gap: '3',
},
item: {
h: '11',
minW: '11',
textStyle: 'md',
px: '4.5',
'& svg': {
width: '5',
height: '5',
},
},
itemText: {
gap: '2',
},
},
xl: {
root: {
gap: '3',
},
item: {
h: '12',
minW: '12',
textStyle: 'md',
px: '5',
'& svg': {
width: '5',
height: '5',
},
},
itemText: {
gap: '2.5',
},
},
},
},
})