SelectionCardGroup β
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
A card-based selection UI for single (radio) or multiple (checkbox) selection. Ideal for onboarding flows, preferences, pricing tiers, and feature opt-ins.
Examples β
Live Preview
Radio Selection (Single)
Select one option from a group of cards
Checkbox Selection (Multiple)
Select multiple options from a group of cards
Theme Variants
Different color themes for various contexts
Default (Primary/Blue)
Success
Warning
Error
Monochrome
Disabled State
Entire group can be disabled
Pricing Tiers Example
Common use case for plan selection
View Vue Code
<template>
<section>
<div class="mbe4">
<h2>Radio Selection (Single)</h2>
<p class="mbs2 mbe3">Select one option from a group of cards</p>
</div>
<VueSelectionCardGroup
type="radio"
name="interests"
legend="Select your primary interest"
class="mbe4"
@selection-change="handleChange"
>
<VueSelectionCard value="tech" label="Technology">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π»</div>
<div style="font-weight: 600;">Technology</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="art" label="Art & Design">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π¨</div>
<div style="font-weight: 600;">Art & Design</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="music" label="Music">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π΅</div>
<div style="font-weight: 600;">Music</div>
</div>
</VueSelectionCard>
</VueSelectionCardGroup>
<div class="mbe4">
<h2>Checkbox Selection (Multiple)</h2>
<p class="mbs2 mbe3">Select multiple options from a group of cards</p>
</div>
<VueSelectionCardGroup
type="checkbox"
name="features"
legend="Select features to enable"
class="mbe4"
@selection-change="handleChange"
>
<VueSelectionCard value="analytics" label="Analytics">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π</div>
<div style="font-weight: 600;">Analytics</div>
<div style="font-size: 0.875rem; color: #666;">Track user behavior</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="notifications" label="Notifications">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π</div>
<div style="font-weight: 600;">Notifications</div>
<div style="font-size: 0.875rem; color: #666;">Push & email alerts</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="export" label="Export">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π€</div>
<div style="font-weight: 600;">Export</div>
<div style="font-size: 0.875rem; color: #666;">Download your data</div>
</div>
</VueSelectionCard>
</VueSelectionCardGroup>
<div class="mbe4">
<h2>Theme Variants</h2>
<p class="mbs2 mbe3">Different color themes for various contexts</p>
</div>
<div style="display: flex; flex-direction: column; gap: 1.5rem;" class="mbe4">
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Default (Primary/Blue)</h3>
<VueSelectionCardGroup
type="radio"
name="theme-default"
legend="Default theme"
legend-hidden
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Success</h3>
<VueSelectionCardGroup
type="radio"
name="theme-success"
legend="Success theme"
legend-hidden
theme="success"
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Warning</h3>
<VueSelectionCardGroup
type="radio"
name="theme-warning"
legend="Warning theme"
legend-hidden
theme="warning"
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Error</h3>
<VueSelectionCardGroup
type="radio"
name="theme-error"
legend="Error theme"
legend-hidden
theme="error"
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Monochrome</h3>
<VueSelectionCardGroup
type="radio"
name="theme-mono"
legend="Monochrome theme"
legend-hidden
theme="monochrome"
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</div>
</div>
<div class="mbe4">
<h2>Disabled State</h2>
<p class="mbs2 mbe3">Entire group can be disabled</p>
</div>
<VueSelectionCardGroup
type="radio"
name="disabled-example"
legend="Disabled group"
:disabled="true"
class="mbe4"
>
<VueSelectionCard value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</VueSelectionCard>
<VueSelectionCard value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</VueSelectionCard>
</VueSelectionCardGroup>
<div class="mbe4">
<h2>Pricing Tiers Example</h2>
<p class="mbs2 mbe3">Common use case for plan selection</p>
</div>
<VueSelectionCardGroup
type="radio"
name="pricing"
legend="Choose your plan"
class="mbe4"
@selection-change="handleChange"
>
<VueSelectionCard value="free" label="Free Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Free</div>
<div style="font-size: 2rem; font-weight: 700; margin: 0.5rem 0;">$0</div>
<div style="color: #666; font-size: 0.875rem;">Perfect for getting started</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="pro" label="Pro Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Pro</div>
<div style="font-size: 2rem; font-weight: 700; margin: 0.5rem 0;">$29</div>
<div style="color: #666; font-size: 0.875rem;">For growing teams</div>
</div>
</VueSelectionCard>
<VueSelectionCard value="premium" label="Premium Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Premium</div>
<div style="font-size: 1.5rem; font-weight: 700; margin: 0.5rem 0;">Custom</div>
<div style="color: #666; font-size: 0.875rem;">For large organizations</div>
</div>
</VueSelectionCard>
</VueSelectionCardGroup>
</section>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { VueSelectionCardGroup } from "agnosticui-core/selection-card-group/vue";
import { VueSelectionCard } from "agnosticui-core/selection-card/vue";
export default defineComponent({
name: "SelectionCardGroupExamples",
components: {
VueSelectionCardGroup,
VueSelectionCard,
},
methods: {
handleChange(detail: { value: string; checked: boolean; selectedValues: string[] }) {
console.log("Selection changed:", detail);
},
},
});
</script>
<style>
/* Responsive: stack cards on mobile */
@media (max-width: 640px) {
ag-selection-card-group::part(ag-selection-card-group-content) {
grid-template-columns: 1fr;
}
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/selection-card-group';
import 'agnosticui-core/selection-card';
export class SelectionCardGroupLitExamples extends LitElement {
// Render in light DOM to access global utility classes
createRenderRoot() {
return this;
}
handleChange(e) {
console.log('Selection changed:', e.detail);
}
render() {
return html`
<section>
<!-- Radio Selection -->
<div class="mbe4">
<h2>Radio Selection (Single)</h2>
<p class="mbs2 mbe3">Select one option from a group of cards</p>
</div>
<ag-selection-card-group
type="radio"
name="interests"
legend="Select your primary interest"
class="mbe4"
@selection-change=${this.handleChange}
>
<ag-selection-card value="tech" label="Technology">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π»</div>
<div style="font-weight: 600;">Technology</div>
</div>
</ag-selection-card>
<ag-selection-card value="art" label="Art & Design">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π¨</div>
<div style="font-weight: 600;">Art & Design</div>
</div>
</ag-selection-card>
<ag-selection-card value="music" label="Music">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π΅</div>
<div style="font-weight: 600;">Music</div>
</div>
</ag-selection-card>
</ag-selection-card-group>
<!-- Checkbox Selection -->
<div class="mbe4">
<h2>Checkbox Selection (Multiple)</h2>
<p class="mbs2 mbe3">Select multiple options from a group of cards</p>
</div>
<ag-selection-card-group
type="checkbox"
name="features"
legend="Select features to enable"
class="mbe4"
@selection-change=${this.handleChange}
>
<ag-selection-card value="analytics" label="Analytics">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π</div>
<div style="font-weight: 600;">Analytics</div>
<div style="font-size: 0.875rem; color: #666;">Track user behavior</div>
</div>
</ag-selection-card>
<ag-selection-card value="notifications" label="Notifications">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π</div>
<div style="font-weight: 600;">Notifications</div>
<div style="font-size: 0.875rem; color: #666;">Push & email alerts</div>
</div>
</ag-selection-card>
<ag-selection-card value="export" label="Export">
<div style="text-align: center; padding: 1rem;">
<div style="font-size: 2rem;">π€</div>
<div style="font-weight: 600;">Export</div>
<div style="font-size: 0.875rem; color: #666;">Download your data</div>
</div>
</ag-selection-card>
</ag-selection-card-group>
<!-- Theme Variants -->
<div class="mbe4">
<h2>Theme Variants</h2>
<p class="mbs2 mbe3">Different color themes for various contexts</p>
</div>
<div style="display: flex; flex-direction: column; gap: 1.5rem;" class="mbe4">
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Default (Primary/Blue)</h3>
<ag-selection-card-group
type="radio"
name="theme-default"
legend="Default theme"
legend-hidden
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Success</h3>
<ag-selection-card-group
type="radio"
name="theme-success"
legend="Success theme"
legend-hidden
theme="success"
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Warning</h3>
<ag-selection-card-group
type="radio"
name="theme-warning"
legend="Warning theme"
legend-hidden
theme="warning"
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Error</h3>
<ag-selection-card-group
type="radio"
name="theme-error"
legend="Error theme"
legend-hidden
theme="error"
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
</div>
<div>
<h3 style="margin-bottom: 0.5rem; font-size: 0.875rem;">Monochrome</h3>
<ag-selection-card-group
type="radio"
name="theme-mono"
legend="Monochrome theme"
legend-hidden
theme="monochrome"
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
</div>
</div>
<!-- Disabled State -->
<div class="mbe4">
<h2>Disabled State</h2>
<p class="mbs2 mbe3">Entire group can be disabled</p>
</div>
<ag-selection-card-group
type="radio"
name="disabled-example"
legend="Disabled group"
disabled
class="mbe4"
>
<ag-selection-card value="a" label="Option A">
<div style="padding: 1rem; text-align: center;">Option A</div>
</ag-selection-card>
<ag-selection-card value="b" label="Option B">
<div style="padding: 1rem; text-align: center;">Option B</div>
</ag-selection-card>
</ag-selection-card-group>
<!-- Pricing Tiers Example -->
<div class="mbe4">
<h2>Pricing Tiers Example</h2>
<p class="mbs2 mbe3">Common use case for plan selection</p>
</div>
<ag-selection-card-group
type="radio"
name="pricing"
legend="Choose your plan"
class="mbe4"
@selection-change=${this.handleChange}
>
<ag-selection-card value="free" label="Free Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Free</div>
<div style="font-size: 2rem; font-weight: 700; margin: 0.5rem 0;">$0</div>
<div style="color: #666; font-size: 0.875rem;">Perfect for getting started</div>
</div>
</ag-selection-card>
<ag-selection-card value="pro" label="Pro Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Pro</div>
<div style="font-size: 2rem; font-weight: 700; margin: 0.5rem 0;">$29</div>
<div style="color: #666; font-size: 0.875rem;">For growing teams</div>
</div>
</ag-selection-card>
<ag-selection-card value="premium" label="Premium Plan">
<div style="padding: 1rem; text-align: center;">
<div style="font-size: 1.5rem; font-weight: 700;">Premium</div>
<div style="font-size: 1.5rem; font-weight: 700; margin: 0.5rem 0;">Custom</div>
<div style="color: #666; font-size: 0.875rem;">For large organizations</div>
</div>
</ag-selection-card>
</ag-selection-card-group>
</section>
`;
}
}
// Register the custom element
customElements.define('selection-card-group-lit-examples', SelectionCardGroupLitExamples);
// Add responsive styles
const style = document.createElement('style');
style.textContent = `
@media (max-width: 640px) {
ag-selection-card-group::part(ag-selection-card-group-content) {
grid-template-columns: 1fr;
}
}
`;
document.head.appendChild(style);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import { ReactSelectionCardGroup } from "agnosticui-core/selection-card-group/react";
import { ReactSelectionCard } from "agnosticui-core/selection-card/react";
export default function SelectionCardGroupExamples() {
const handleChange = (e) => {
console.log("Selection changed:", e.detail);
};
return (
<section>
{/* Radio Selection */}
<div className="mbe4">
<h2>Radio Selection (Single)</h2>
<p className="mbs2 mbe3">Select one option from a group of cards</p>
</div>
<ReactSelectionCardGroup
type="radio"
name="interests"
legend="Select your primary interest"
className="mbe4"
onSelectionChange={handleChange}
>
<ReactSelectionCard value="tech" label="Technology">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π»</div>
<div style={{ fontWeight: 600 }}>Technology</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="art" label="Art & Design">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π¨</div>
<div style={{ fontWeight: 600 }}>Art & Design</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="music" label="Music">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π΅</div>
<div style={{ fontWeight: 600 }}>Music</div>
</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
{/* Checkbox Selection */}
<div className="mbe4">
<h2>Checkbox Selection (Multiple)</h2>
<p className="mbs2 mbe3">Select multiple options from a group of cards</p>
</div>
<ReactSelectionCardGroup
type="checkbox"
name="features"
legend="Select features to enable"
className="mbe4"
onSelectionChange={handleChange}
>
<ReactSelectionCard value="analytics" label="Analytics">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π</div>
<div style={{ fontWeight: 600 }}>Analytics</div>
<div style={{ fontSize: "0.875rem", color: "#666" }}>Track user behavior</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="notifications" label="Notifications">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π</div>
<div style={{ fontWeight: 600 }}>Notifications</div>
<div style={{ fontSize: "0.875rem", color: "#666" }}>Push & email alerts</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="export" label="Export">
<div style={{ textAlign: "center", padding: "1rem" }}>
<div style={{ fontSize: "2rem" }}>π€</div>
<div style={{ fontWeight: 600 }}>Export</div>
<div style={{ fontSize: "0.875rem", color: "#666" }}>Download your data</div>
</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
{/* Theme Variants */}
<div className="mbe4">
<h2>Theme Variants</h2>
<p className="mbs2 mbe3">Different color themes for various contexts</p>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "1.5rem" }} className="mbe4">
<div>
<h3 style={{ marginBottom: "0.5rem", fontSize: "0.875rem" }}>Default (Primary/Blue)</h3>
<ReactSelectionCardGroup
type="radio"
name="theme-default"
legend="Default theme"
legendHidden
>
<ReactSelectionCard value="a" label="Option A">
<div style={{ padding: "1rem", textAlign: "center" }}>Option A</div>
</ReactSelectionCard>
<ReactSelectionCard value="b" label="Option B">
<div style={{ padding: "1rem", textAlign: "center" }}>Option B</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
</div>
<div>
<h3 style={{ marginBottom: "0.5rem", fontSize: "0.875rem" }}>Success</h3>
<ReactSelectionCardGroup
type="radio"
name="theme-success"
legend="Success theme"
legendHidden
theme="success"
>
<ReactSelectionCard value="a" label="Option A">
<div style={{ padding: "1rem", textAlign: "center" }}>Option A</div>
</ReactSelectionCard>
<ReactSelectionCard value="b" label="Option B">
<div style={{ padding: "1rem", textAlign: "center" }}>Option B</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
</div>
<div>
<h3 style={{ marginBottom: "0.5rem", fontSize: "0.875rem" }}>Monochrome</h3>
<ReactSelectionCardGroup
type="radio"
name="theme-mono"
legend="Monochrome theme"
legendHidden
theme="monochrome"
>
<ReactSelectionCard value="a" label="Option A">
<div style={{ padding: "1rem", textAlign: "center" }}>Option A</div>
</ReactSelectionCard>
<ReactSelectionCard value="b" label="Option B">
<div style={{ padding: "1rem", textAlign: "center" }}>Option B</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
</div>
</div>
{/* Disabled State */}
<div className="mbe4">
<h2>Disabled State</h2>
<p className="mbs2 mbe3">Entire group can be disabled</p>
</div>
<ReactSelectionCardGroup
type="radio"
name="disabled-example"
legend="Disabled group"
disabled
className="mbe4"
>
<ReactSelectionCard value="a" label="Option A">
<div style={{ padding: "1rem", textAlign: "center" }}>Option A</div>
</ReactSelectionCard>
<ReactSelectionCard value="b" label="Option B">
<div style={{ padding: "1rem", textAlign: "center" }}>Option B</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
{/* Pricing Tiers Example */}
<div className="mbe4">
<h2>Pricing Tiers Example</h2>
<p className="mbs2 mbe3">Common use case for plan selection</p>
</div>
<ReactSelectionCardGroup
type="radio"
name="pricing"
legend="Choose your plan"
className="mbe4"
onSelectionChange={handleChange}
>
<ReactSelectionCard value="free" label="Free Plan">
<div style={{ padding: "1rem", textAlign: "center" }}>
<div style={{ fontSize: "1.5rem", fontWeight: 700 }}>Free</div>
<div style={{ fontSize: "2rem", fontWeight: 700, margin: "0.5rem 0" }}>$0</div>
<div style={{ color: "#666", fontSize: "0.875rem" }}>Perfect for getting started</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="pro" label="Pro Plan">
<div style={{ padding: "1rem", textAlign: "center" }}>
<div style={{ fontSize: "1.5rem", fontWeight: 700 }}>Pro</div>
<div style={{ fontSize: "2rem", fontWeight: 700, margin: "0.5rem 0" }}>$29</div>
<div style={{ color: "#666", fontSize: "0.875rem" }}>For growing teams</div>
</div>
</ReactSelectionCard>
<ReactSelectionCard value="premium" label="Premium Plan">
<div style={{ padding: "1rem", textAlign: "center" }}>
<div style={{ fontSize: "1.5rem", fontWeight: 700 }}>Premium</div>
<div style={{ fontSize: "1.5rem", fontWeight: 700, margin: "0.5rem 0" }}>Custom</div>
<div style={{ color: "#666", fontSize: "0.875rem" }}>For large organizations</div>
</div>
</ReactSelectionCard>
</ReactSelectionCardGroup>
</section>
);
}
Usage β
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add SelectionCardGroup
npx ag add SelectionCardThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Vue
<template>
<VueSelectionCardGroup
type="radio"
name="interests"
legend="Select your interests"
@selection-change="handleChange"
>
<VueSelectionCard value="tech" label="Technology">
<span>Technology</span>
</VueSelectionCard>
<VueSelectionCard value="art" label="Art & Design">
<span>Art & Design</span>
</VueSelectionCard>
</VueSelectionCardGroup>
</template>
<script setup>
import { VueSelectionCardGroup } from 'agnosticui-core/selection-card-group/vue';
import { VueSelectionCard } from 'agnosticui-core/selection-card/vue';
const handleChange = (e) => {
console.log('Selected:', e.detail.selectedValues);
};
</script>React
import { ReactSelectionCardGroup } from "agnosticui-core/selection-card-group/react";
import { ReactSelectionCard } from "agnosticui-core/selection-card/react";
export default function Example() {
const handleChange = (e) => {
console.log('Selected:', e.detail.selectedValues);
};
return (
<ReactSelectionCardGroup
type="radio"
name="interests"
legend="Select your interests"
onSelectionChange={handleChange}
>
<ReactSelectionCard value="tech" label="Technology">
<span>Technology</span>
</ReactSelectionCard>
<ReactSelectionCard value="art" label="Art & Design">
<span>Art & Design</span>
</ReactSelectionCard>
</ReactSelectionCardGroup>
);
}Lit (Web Components)
<script type="module">
import "agnosticui-core/selection-card-group";
import "agnosticui-core/selection-card";
const group = document.querySelector('ag-selection-card-group');
group.addEventListener('selection-change', (e) => {
console.log('Selected:', e.detail.selectedValues);
});
</script>
<ag-selection-card-group type="radio" name="interests" legend="Select your interests">
<ag-selection-card value="tech" label="Technology">
<span>Technology</span>
</ag-selection-card>
<ag-selection-card value="art" label="Art & Design">
<span>Art & Design</span>
</ag-selection-card>
</ag-selection-card-group>Props β
SelectionCardGroup β
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'radio' | 'checkbox' | 'radio' | Selection mode |
name | string | '' | Input name attribute (required) |
legend | string | '' | Accessible group label |
legend-hidden | boolean | false | Visually hide legend |
theme | '' | 'success' | 'info' | 'warning' | 'error' | 'monochrome' | '' | Theme variant (empty = primary/blue) |
value | string | '' | Controlled value (radio) |
values | string[] | [] | Controlled values (checkbox) |
disabled | boolean | false | Disable all cards |
SelectionCard β
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | '' | Unique value (required) |
label | string | '' | Accessible label (required) |
checked | boolean | false | Selection state (managed by group) |
disabled | boolean | false | Disable this card |
Events β
selection-change β
Fired when selection changes.
interface SelectionChangeEventDetail {
value: string; // Value that triggered the change
checked: boolean; // Whether the card is now selected
selectedValues: string[]; // All currently selected values
}Themes β
The theme prop controls the color scheme for selected cards:
| Theme | Description |
|---|---|
'' (default) | Primary blue - uses --ag-primary-* tokens |
success | Green - uses --ag-success-* tokens |
info | Cyan/blue - uses --ag-info-* tokens |
warning | Yellow/orange - uses --ag-warning-* tokens |
error | Red - uses --ag-danger-* tokens |
monochrome | Black/white - uses --ag-black and inverted tokens |
<!-- Success theme -->
<ag-selection-card-group type="radio" name="status" theme="success">
...
</ag-selection-card-group>Styling β
CSS Custom Properties β
/* Card sizing & spacing */
--ag-selection-card-padding: var(--ag-space-4);
--ag-selection-card-gap: var(--ag-space-3);
--ag-selection-card-border-radius: var(--ag-radius-md);
--ag-selection-card-indicator-size: var(--ag-space-5);
/* Card colors - unselected */
--ag-selection-card-background: var(--ag-background-primary);
--ag-selection-card-border-color: var(--ag-border);
/* Card colors - selected */
--ag-selection-card-selected-background: var(--ag-primary-background);
--ag-selection-card-selected-border-color: var(--ag-primary);
--ag-selection-card-indicator-color: var(--ag-primary);
/* Group layout */
--ag-selection-card-group-gap: var(--ag-space-4);CSS Parts β
SelectionCardGroup β
| Part | Description |
|---|---|
ag-selection-card-group-fieldset | The fieldset element |
ag-selection-card-group-legend | The legend element |
ag-selection-card-group-content | The content wrapper (grid) |
SelectionCard β
| Part | Description |
|---|---|
ag-selection-card-container | The outer clickable label |
ag-selection-card-control | The hidden input element |
ag-selection-card-indicator | The selection indicator (filled circle for radio, checkmark for checkbox) |
ag-selection-card-content | The slotted content wrapper |
CSS Parts Example β
/* Custom indicator size and shape */
ag-selection-card::part(ag-selection-card-indicator) {
width: 1.5rem;
height: 1.5rem;
}
/* Custom container styling */
ag-selection-card::part(ag-selection-card-container) {
border-radius: var(--ag-radius-lg);
}
/* Responsive: stack cards on mobile */
@media (max-width: 640px) {
ag-selection-card-group::part(ag-selection-card-group-content) {
grid-template-columns: 1fr;
}
}Accessibility β
- Uses
<fieldset>and<legend>for proper group semantics - Each card has a required
labelprop for screen readers - Keyboard navigation:
- Arrow keys: Navigate between cards (selects in radio mode)
- Space/Enter: Toggle selection
- Home/End: Jump to first/last card
- Focus ring visible on keyboard navigation
role="radiogroup"for radio mode,role="group"for checkbox mode