A wrapper for OptionCard components.

Importing

In a React app, the component can be imported via:

import { OptionCardGroup } from '@customerio/pluma-components/react';

In an Ember app, the component is named PlumaOptionCardGroup.

Usage

An OptionCardGroup should contain OptionCard components as children. OptionCardGroup will forward the name attribute to any Checkboxes nested within, as well as connect onChange handlers to them, so there's no need to define those props on the OptionCards themselves:

Test option card group
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [value, setValue] = useState('one');

	return <OptionCardGroup
		label="Test option card group"
		value={value}
		onChange={(value) => {
			setValue(value);
		}}
	>
		<OptionCard value="one" title="One" />
		<OptionCard value="two" title="Two" />
		<OptionCard value="three" title="Three" />
	</OptionCardGroup>
}

Or, in Ember:

Loading...

Labels

An OptionCardGroup must always have an associated label. The component accepts a label string prop, which renders text above the nested checkboxes.

Alternatively, ariaLabelledby may be used to associate the group with a label elsewhere in the DOM. To make sure the association is set up both ways, it's recommended to also set for on the label, pointing to an id on the checkbox group:

import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [value, setValue] = useState(null);

	return <>
		<Box
			as="label"
			id="my_label_id"
			htmlFor="my_group"
		>
			Make a selection
		</Box>
		<OptionCardGroup
			id="my_input"
			ariaLabelledby="my_label_id"
			value={value}
			onChange={(value) => {
				setValue(value);
			}}
		>
			<OptionCard value="one" title="One" />
			<OptionCard value="two" title="Two" />
			<OptionCard value="three" title="Three" />
		</OptionCardGroup>
	</>;
}

Finally, the ariaLabel prop can be used if no other element is suitable for a label.

Disabled groups

The isDisabled prop on an OptionCardGroup will take precedence over the isDisabled prop on individual OptionCard components.

It is not necessary to set isDisabled on the individual OptionCard components, as the OptionCardGroup provides that state to the cards through its context.

Test checkbox group
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [isDisabled, setIsDisabled] = useState(false);
	const [value, setValue] = useState('one');
	return <>		
		<Box as="label" mb="200" display="block">
			<Checkbox
				label="Disable group"
				isChecked={isDisabled}
				onChange={(e) => {
					setIsDisabled(e.currentTarget.checked);
				}}
			/>
		</Box>

		<OptionCardGroup
			label="Test checkbox group"
			isDisabled={isDisabled}
			value={value}
			onChange={(value) => {
				setValue(value);
			}}
		>
			<OptionCard value="one" title="One" isDisabled={false} />
			<OptionCard value="two" title="Two" isDisabled={false} />
			<OptionCard value="three" title="Three" isDisabled={true} />
		</OptionCardGroup>
	</>
}

Input type

An inputType can be set o the OptionCardGroup, which will be passed down into the nested OptionCards:

Test checkbox option card group
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [values, setValues] = useState(['two']);

	return <OptionCardGroup
		label="Test checkbox option card group"
		inputType="checkbox"
		value={values}
		onChange={(values) => {
			setValues(values);
		}}
	>
		<OptionCard value="one" title="One" />
		<OptionCard value="two" title="Two" />
		<OptionCard value="three" title="Three" />
	</OptionCardGroup>
}

Preventing selection

Just like in the OptionCard component, selection can be prevented with the canSelect prop. Note that deselecting is still allowed.

This is useful in cases where you need to limit a checkbox-based selection to a maximum number of options.

Test checkbox option card group
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [values, setValues] = useState(['two', 'three']);

	return <OptionCardGroup
		label="Test checkbox option card group"
		inputType="checkbox"
		canSelect={values.length < 2}
		value={values}
		onChange={(values) => {
			setValues(values);
		}}
	>
		<OptionCard value="one" title="One" />
		<OptionCard value="two" title="Two" />
		<OptionCard value="three" title="Three" />
	</OptionCardGroup>
}

Size

The Option Card Group component accepts a size prop that controls the size of all option cards within the group. This allows you to easily set a consistent size for all cards in the group without having to specify it on each individual card.

Size Example
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('one');

  return (
    <>
      <OptionCardGroup
        label="Size Example"
        value={value}
        onChange={(value) => {
          setValue(value);
        }}
        size='sm'
      >
        <OptionCard value="one" description="This is the first option" />
        <OptionCard value="two" description="This is the second option" />
        <OptionCard value="three" description="This is the third option" />
      </OptionCardGroup>
    </>
  );
}

The size property accepts either "md" (default) or "sm" as values.

Layout

By default, the cards will render in a flex container, with a gap of 200 and no wrapping. The layout of the card container can be customized through the following properties:

For example:

Test cards
import { OptionCard, OptionCardGroup } from '@customerio/pluma-components/react';
import { useState } from 'react';

export default function Example() {
	const [values, setValues] = useState([]);

	return <div style={{maxWidth: 400}}>
			<OptionCardGroup
				label="Test cards"
				inputType="checkbox"
				value={values}
				onChange={(values) => {
					setValues(values);
				}}
				shouldWrapCards={true}
				cardsGap="025"
			>
				{[...new Array(20)].map((_, i) => (
					<OptionCard key={i} value={String(i)} description={'Card ' + i} />
				))}
			</OptionCardGroup>
		</div>

}

API

The aria-label attribute to be applied on the fieldset

The aria-labelledby attribute to be applied on the fieldset

This option prevents selection of cards. Unlike isDisabled, however, it will not prevent the deselection of currently selected cards.

Default:row

The flex-direction style of the card container

An optional id attribute to assign to the fieldset

Default:radio

Whether the cards in the group represent radio or checkbox inputs.

Whether the entire group is disabled

The label text to be shown above the option card group

The name shared by option cards in this group. If none is provided, one will be generated

Default:false

Whether the cards should wrap (sets flex-wrap to wrap or nowrap)

Default:md

The size of all option cards in the group

The current value. If the inputType is radio, the value is a string. When the inputType is checkbox, the value is an array of strings.