Skip to content

SelectionButtonGroup

Experimental Alpha

This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.

A button-styled selection UI for single (radio) or multiple (checkbox) selection. Ideal for compact option toggles, filter controls, and inline selections.

Examples

Vue
Lit
React
Live Preview

Radio Group (Single Selection)

Credit Card PayPal Bank Transfer

Selected:

Checkbox Group (Multiple Selection)

Extra Cheese Pepperoni Mushrooms Olives

Selected: None

Theme Variants

Default (Primary)

AB

Success

AB

Info

AB

Warning

AB

Error

AB

Monochrome

AB

Size Variants

Small (sm)

Option AOption B

Medium (md) - Default

Option AOption B

Large (lg)

Option AOption B

Shape Variants

Default (rectangular)

Option AOption B

Rounded

Option AOption B

Capsule (pill)

Option AOption B

Disabled State

Option AOption BOption C

Disabled Individual Button State

Option AOption BOption COption DOption E
View Vue Code
<template>
  <div class="examples-container">
    <!-- Radio Group -->
    <section class="example-section">
      <h3>Radio Group (Single Selection)</h3>
      <VueSelectionButtonGroup
        type="radio"
        name="payment-method"
        legend="Select payment method"
        shape="rounded"
        @selection-change="handleChange"
      >
        <VueSelectionButton value="card" label="Credit Card">
          Credit Card
        </VueSelectionButton>
        <VueSelectionButton value="paypal" label="PayPal">
          PayPal
        </VueSelectionButton>
        <VueSelectionButton value="bank" label="Bank Transfer">
          Bank Transfer
        </VueSelectionButton>
      </VueSelectionButtonGroup>
      <p class="selection-output">Selected: {{ radioSelection }}</p>
    </section>

    <!-- Checkbox Group -->
    <section class="example-section">
      <h3>Checkbox Group (Multiple Selection)</h3>
      <VueSelectionButtonGroup
        type="checkbox"
        name="toppings"
        legend="Select toppings"
        shape="rounded"
        @selection-change="handleCheckboxChange"
      >
        <VueSelectionButton value="cheese" label="Extra Cheese">
          Extra Cheese
        </VueSelectionButton>
        <VueSelectionButton value="pepperoni" label="Pepperoni">
          Pepperoni
        </VueSelectionButton>
        <VueSelectionButton value="mushrooms" label="Mushrooms">
          Mushrooms
        </VueSelectionButton>
        <VueSelectionButton value="olives" label="Olives">
          Olives
        </VueSelectionButton>
      </VueSelectionButtonGroup>
      <p class="selection-output">Selected: {{ checkboxSelection.join(', ') || 'None' }}</p>
    </section>

    <!-- Theme Variants -->
    <section class="example-section">
      <h3>Theme Variants</h3>
      <div class="theme-grid">
        <div>
          <p class="theme-label">Default (Primary)</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-default"
            legend="Default theme"
            legend-hidden
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="theme-label">Success</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-success"
            legend="Success theme"
            legend-hidden
            theme="success"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="theme-label">Info</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-info"
            legend="Info theme"
            legend-hidden
            theme="info"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="theme-label">Warning</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-warning"
            legend="Warning theme"
            legend-hidden
            theme="warning"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="theme-label">Error</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-error"
            legend="Error theme"
            legend-hidden
            theme="error"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="theme-label">Monochrome</p>
          <VueSelectionButtonGroup
            type="radio"
            name="theme-monochrome"
            legend="Monochrome theme"
            legend-hidden
            theme="monochrome"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
      </div>
    </section>

    <!-- Size Variants -->
    <section class="example-section">
      <h3>Size Variants</h3>
      <div class="size-grid">
        <div>
          <p class="size-label">Small (sm)</p>
          <VueSelectionButtonGroup
            type="radio"
            name="size-sm"
            legend="Small size"
            legend-hidden
            size="sm"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="size-label">Medium (md) - Default</p>
          <VueSelectionButtonGroup
            type="radio"
            name="size-md"
            legend="Medium size"
            legend-hidden
            size="md"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="size-label">Large (lg)</p>
          <VueSelectionButtonGroup
            type="radio"
            name="size-lg"
            legend="Large size"
            legend-hidden
            size="lg"
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
      </div>
    </section>

    <!-- Shape Variants -->
    <section class="example-section">
      <h3>Shape Variants</h3>
      <div class="shape-grid">
        <div>
          <p class="shape-label">Default (rectangular)</p>
          <VueSelectionButtonGroup
            type="radio"
            name="shape-default"
            legend="Default shape"
            legend-hidden
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="shape-label">Rounded</p>
          <VueSelectionButtonGroup
            type="radio"
            name="shape-rounded"
            legend="Rounded shape"
            legend-hidden
            shape="rounded"
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
        <div>
          <p class="shape-label">Capsule (pill)</p>
          <VueSelectionButtonGroup
            type="radio"
            name="shape-capsule"
            legend="Capsule shape"
            legend-hidden
            shape="capsule"
          >
            <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
            <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
          </VueSelectionButtonGroup>
        </div>
      </div>
    </section>

    <!-- Disabled State -->
    <section class="example-section">
      <h3>Disabled State</h3>
      <VueSelectionButtonGroup
        type="radio"
        name="disabled-example"
        legend="Disabled group"
        shape="rounded"
        disabled
      >
        <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
        <VueSelectionButton value="b" label="Option B">Option B</VueSelectionButton>
        <VueSelectionButton value="c" label="Option C">Option C</VueSelectionButton>
      </VueSelectionButtonGroup>
    </section>
    <section class="example-section">
      <h3>Disabled Individual Button State</h3>
      <VueSelectionButtonGroup
        type="radio"
        name="disabled-button-example"
        legend="Disabled individual"
        shape="rounded"
      >
        <VueSelectionButton value="a" label="Option A">Option A</VueSelectionButton>
        <VueSelectionButton disabled value="b" label="Option B">Option B</VueSelectionButton>
        <VueSelectionButton value="c" label="Option C">Option C</VueSelectionButton>
        <VueSelectionButton disabled value="d" label="Option D">Option D</VueSelectionButton>
        <VueSelectionButton value="e" label="Option E">Option E</VueSelectionButton>
      </VueSelectionButtonGroup>
    </section>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { VueSelectionButtonGroup } from 'agnosticui-core/selection-button-group/vue';
import { VueSelectionButton } from 'agnosticui-core/selection-button/vue';

const radioSelection = ref('');
const checkboxSelection = ref<string[]>([]);

const handleChange = (e: CustomEvent) => {
  radioSelection.value = e.detail.selectedValues[0] || '';
};

const handleCheckboxChange = (e: CustomEvent) => {
  checkboxSelection.value = e.detail.selectedValues;
};
</script>

<style scoped>
.examples-container {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.example-section {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.example-section h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}

.selection-output {
  margin: 0;
  font-size: 0.875rem;
  color: var(--vp-c-text-2);
}

.theme-grid,
.size-grid,
.shape-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
}

.theme-label,
.size-label,
.shape-label {
  margin: 0 0 0.5rem 0;
  font-size: 0.875rem;
  color: var(--vp-c-text-2);
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html, css } from 'lit';
import 'agnosticui-core/selection-button-group';
import 'agnosticui-core/selection-button';

export class SelectionButtonGroupLitExamples extends LitElement {
  static styles = css`
    :host {
      display: block;
    }

    .examples-container {
      display: flex;
      flex-direction: column;
      gap: 2rem;
    }

    .example-section {
      display: flex;
      flex-direction: column;
      gap: 0.75rem;
    }

    .example-section h3 {
      margin: 0;
      font-size: 1rem;
      font-weight: 600;
    }

    .selection-output {
      margin: 0;
      font-size: 0.875rem;
      color: var(--vp-c-text-2, #666);
    }

    .theme-grid,
    .size-grid,
    .shape-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 1rem;
    }

    .theme-label,
    .size-label,
    .shape-label {
      margin: 0 0 0.5rem 0;
      font-size: 0.875rem;
      color: var(--vp-c-text-2, #666);
    }
  `;

  static properties = {
    radioSelection: { type: String },
    checkboxSelection: { type: Array },
  };

  constructor() {
    super();
    this.radioSelection = '';
    this.checkboxSelection = [];
  }

  _handleRadioChange(e) {
    this.radioSelection = e.detail.selectedValues[0] || '';
  }

  _handleCheckboxChange(e) {
    this.checkboxSelection = [...e.detail.selectedValues];
  }

  render() {
    return html`
      <div class="examples-container">
        <!-- Radio Group -->
        <section class="example-section">
          <h3>Radio Group (Single Selection)</h3>
          <ag-selection-button-group
            type="radio"
            name="payment-method"
            legend="Select payment method"
            shape="rounded"
            @selection-change=${this._handleRadioChange}
          >
            <ag-selection-button value="card" label="Credit Card">
              Credit Card
            </ag-selection-button>
            <ag-selection-button value="paypal" label="PayPal">
              PayPal
            </ag-selection-button>
            <ag-selection-button value="bank" label="Bank Transfer">
              Bank Transfer
            </ag-selection-button>
          </ag-selection-button-group>
          <p class="selection-output">Selected: ${this.radioSelection || 'None'}</p>
        </section>

        <!-- Checkbox Group -->
        <section class="example-section">
          <h3>Checkbox Group (Multiple Selection)</h3>
          <ag-selection-button-group
            type="checkbox"
            name="toppings"
            legend="Select toppings"
            shape="rounded"
            @selection-change=${this._handleCheckboxChange}
          >
            <ag-selection-button value="cheese" label="Extra Cheese">
              Extra Cheese
            </ag-selection-button>
            <ag-selection-button value="pepperoni" label="Pepperoni">
              Pepperoni
            </ag-selection-button>
            <ag-selection-button value="mushrooms" label="Mushrooms">
              Mushrooms
            </ag-selection-button>
            <ag-selection-button value="olives" label="Olives">
              Olives
            </ag-selection-button>
          </ag-selection-button-group>
          <p class="selection-output">Selected: ${this.checkboxSelection.join(', ') || 'None'}</p>
        </section>

        <!-- Theme Variants -->
        <section class="example-section">
          <h3>Theme Variants</h3>
          <div class="theme-grid">
            <div>
              <p class="theme-label">Default (Primary)</p>
              <ag-selection-button-group
                type="radio"
                name="theme-default"
                legend="Default theme"
                legend-hidden
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="theme-label">Success</p>
              <ag-selection-button-group
                type="radio"
                name="theme-success"
                legend="Success theme"
                legend-hidden
                theme="success"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="theme-label">Info</p>
              <ag-selection-button-group
                type="radio"
                name="theme-info"
                legend="Info theme"
                legend-hidden
                theme="info"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="theme-label">Warning</p>
              <ag-selection-button-group
                type="radio"
                name="theme-warning"
                legend="Warning theme"
                legend-hidden
                theme="warning"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="theme-label">Error</p>
              <ag-selection-button-group
                type="radio"
                name="theme-error"
                legend="Error theme"
                legend-hidden
                theme="error"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="theme-label">Monochrome</p>
              <ag-selection-button-group
                type="radio"
                name="theme-monochrome"
                legend="Monochrome theme"
                legend-hidden
                theme="monochrome"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">B</ag-selection-button>
              </ag-selection-button-group>
            </div>
          </div>
        </section>

        <!-- Size Variants -->
        <section class="example-section">
          <h3>Size Variants</h3>
          <div class="size-grid">
            <div>
              <p class="size-label">Small (sm)</p>
              <ag-selection-button-group
                type="radio"
                name="size-sm"
                legend="Small size"
                legend-hidden
                size="sm"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="size-label">Medium (md) - Default</p>
              <ag-selection-button-group
                type="radio"
                name="size-md"
                legend="Medium size"
                legend-hidden
                size="md"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="size-label">Large (lg)</p>
              <ag-selection-button-group
                type="radio"
                name="size-lg"
                legend="Large size"
                legend-hidden
                size="lg"
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
          </div>
        </section>

        <!-- Shape Variants -->
        <section class="example-section">
          <h3>Shape Variants</h3>
          <div class="shape-grid">
            <div>
              <p class="shape-label">Default (rectangular)</p>
              <ag-selection-button-group
                type="radio"
                name="shape-default"
                legend="Default shape"
                legend-hidden
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="shape-label">Rounded</p>
              <ag-selection-button-group
                type="radio"
                name="shape-rounded"
                legend="Rounded shape"
                legend-hidden
                shape="rounded"
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
            <div>
              <p class="shape-label">Capsule (pill)</p>
              <ag-selection-button-group
                type="radio"
                name="shape-capsule"
                legend="Capsule shape"
                legend-hidden
                shape="capsule"
              >
                <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
                <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
              </ag-selection-button-group>
            </div>
          </div>
        </section>
        <!-- Disabled Group State -->
        <section class="example-section">
          <h3>Disabled Group State</h3>
          <ag-selection-button-group
            type="radio"
            name="disabled-group-example"
            legend="Disabled group"
            shape="rounded"
            disabled
          >
            <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
            <ag-selection-button value="b" label="Option B">Option B</ag-selection-button>
            <ag-selection-button value="c" label="Option C">Option C</ag-selection-button>
          </ag-selection-button-group>
        </section>
        <!-- Disabled Buttons State -->
        <section class="example-section">
          <h3>Disabled Individual Buttons State</h3>
          <ag-selection-button-group
            type="radio"
            name="disabled-buttons-example"
            legend="Disabled individual buttons"
            shape="rounded"
          >
            <ag-selection-button value="a" label="Option A">Option A</ag-selection-button>
            <ag-selection-button disabled value="b" label="Option B">Option B</ag-selection-button>
            <ag-selection-button value="c" label="Option C">Option C</ag-selection-button>
            <ag-selection-button disabled value="d" label="Option D">Option D</ag-selection-button>
            <ag-selection-button value="e" label="Option E">Option E</ag-selection-button>
          </ag-selection-button-group>
        </section>
      </div>
    `;
  }
}

customElements.define('selection-button-group-lit-examples', SelectionButtonGroupLitExamples);

Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.

View React Code
import { useState } from 'react';
import { ReactSelectionButtonGroup } from 'agnosticui-core/selection-button-group/react';
import { ReactSelectionButton } from 'agnosticui-core/selection-button/react';

export default function SelectionButtonGroupReactExamples() {
  const [radioSelection, setRadioSelection] = useState('');
  const [checkboxSelection, setCheckboxSelection] = useState([]);

  const handleRadioChange = (e) => {
    setRadioSelection(e.detail.selectedValues[0] || '');
  };

  const handleCheckboxChange = (e) => {
    setCheckboxSelection(e.detail.selectedValues);
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
      {/* Radio Group */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>
          Radio Group (Single Selection)
        </h3>
        <ReactSelectionButtonGroup
          type="radio"
          name="payment-method"
          legend="Select payment method"
          shape="rounded"
          onSelectionChange={handleRadioChange}
        >
          <ReactSelectionButton value="card" label="Credit Card">
            Credit Card
          </ReactSelectionButton>
          <ReactSelectionButton value="paypal" label="PayPal">
            PayPal
          </ReactSelectionButton>
          <ReactSelectionButton value="bank" label="Bank Transfer">
            Bank Transfer
          </ReactSelectionButton>
        </ReactSelectionButtonGroup>
        <p style={{ margin: 0, fontSize: '0.875rem', color: '#666' }}>
          Selected: {radioSelection || 'None'}
        </p>
      </section>

      {/* Checkbox Group */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>
          Checkbox Group (Multiple Selection)
        </h3>
        <ReactSelectionButtonGroup
          type="checkbox"
          name="toppings"
          legend="Select toppings"
          shape="rounded"
          onSelectionChange={handleCheckboxChange}
        >
          <ReactSelectionButton value="cheese" label="Extra Cheese">
            Extra Cheese
          </ReactSelectionButton>
          <ReactSelectionButton value="pepperoni" label="Pepperoni">
            Pepperoni
          </ReactSelectionButton>
          <ReactSelectionButton value="mushrooms" label="Mushrooms">
            Mushrooms
          </ReactSelectionButton>
          <ReactSelectionButton value="olives" label="Olives">
            Olives
          </ReactSelectionButton>
        </ReactSelectionButtonGroup>
        <p style={{ margin: 0, fontSize: '0.875rem', color: '#666' }}>
          Selected: {checkboxSelection.join(', ') || 'None'}
        </p>
      </section>

      {/* Theme Variants */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>Theme Variants</h3>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1rem' }}>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Default (Primary)</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-default"
              legend="Default theme"
              legendHidden
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Success</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-success"
              legend="Success theme"
              legendHidden
              theme="success"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Info</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-info"
              legend="Info theme"
              legendHidden
              theme="info"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Warning</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-warning"
              legend="Warning theme"
              legendHidden
              theme="warning"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Error</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-error"
              legend="Error theme"
              legendHidden
              theme="error"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Monochrome</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="theme-monochrome"
              legend="Monochrome theme"
              legendHidden
              theme="monochrome"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
        </div>
      </section>

      {/* Size Variants */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>Size Variants</h3>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1rem' }}>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Small (sm)</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="size-sm"
              legend="Small size"
              legendHidden
              size="sm"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Medium (md) - Default</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="size-md"
              legend="Medium size"
              legendHidden
              size="md"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Large (lg)</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="size-lg"
              legend="Large size"
              legendHidden
              size="lg"
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
        </div>
      </section>

      {/* Shape Variants */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>Shape Variants</h3>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1rem' }}>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Default (rectangular)</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="shape-default"
              legend="Default shape"
              legendHidden
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Rounded</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="shape-rounded"
              legend="Rounded shape"
              legendHidden
              shape="rounded"
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
          <div>
            <p style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#666' }}>Capsule (pill)</p>
            <ReactSelectionButtonGroup
              type="radio"
              name="shape-capsule"
              legend="Capsule shape"
              legendHidden
              shape="capsule"
            >
              <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
              <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
            </ReactSelectionButtonGroup>
          </div>
        </div>
      </section>

      {/* Disabled State */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>Disabled Group State</h3>
        <ReactSelectionButtonGroup
          type="radio"
          name="disabled-example"
          legend="Disabled group"
          shape="rounded"
          disabled
        >
          <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
          <ReactSelectionButton value="b" label="Option B">Option B</ReactSelectionButton>
          <ReactSelectionButton value="c" label="Option C">Option C</ReactSelectionButton>
        </ReactSelectionButtonGroup>
      </section>
      {/* Disabled State */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
        <h3 style={{ margin: 0, fontSize: '1rem', fontWeight: 600 }}>Disabled Individual Button State</h3>
        <ReactSelectionButtonGroup
          type="radio"
          name="disabled-buttons-example"
          legend="Disabled buttons"
          shape="rounded"
        >
          <ReactSelectionButton value="a" label="Option A">Option A</ReactSelectionButton>
          <ReactSelectionButton disabled value="b" label="Option B">Option B</ReactSelectionButton>
          <ReactSelectionButton value="c" label="Option C">Option C</ReactSelectionButton>
          <ReactSelectionButton disabled value="c" label="Option D">Option D</ReactSelectionButton>
          <ReactSelectionButton value="c" label="Option E">Option E</ReactSelectionButton>
        </ReactSelectionButtonGroup>
      </section>
    </div>
  );
}
Open in StackBlitz

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:

bash
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add SelectionButtonGroup
npx ag add SelectionButton

The 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
vue
<template>
  <VueSelectionButtonGroup
    type="radio"
    name="payment"
    legend="Select payment method"
    shape="rounded"
    @selection-change="handleChange"
  >
    <VueSelectionButton value="card" label="Credit Card">
      Credit Card
    </VueSelectionButton>
    <VueSelectionButton value="paypal" label="PayPal">
      PayPal
    </VueSelectionButton>
  </VueSelectionButtonGroup>
</template>

<script setup>
import { VueSelectionButtonGroup } from 'agnosticui-core/selection-button-group/vue';
import { VueSelectionButton } from 'agnosticui-core/selection-button/vue';

const handleChange = (e) => {
  console.log('Selected:', e.detail.selectedValues);
};
</script>
React
tsx
import { ReactSelectionButtonGroup } from "agnosticui-core/selection-button-group/react";
import { ReactSelectionButton } from "agnosticui-core/selection-button/react";

export default function Example() {
  const handleChange = (e) => {
    console.log('Selected:', e.detail.selectedValues);
  };

  return (
    <ReactSelectionButtonGroup
      type="radio"
      name="payment"
      legend="Select payment method"
      shape="rounded"
      onSelectionChange={handleChange}
    >
      <ReactSelectionButton value="card" label="Credit Card">
        Credit Card
      </ReactSelectionButton>
      <ReactSelectionButton value="paypal" label="PayPal">
        PayPal
      </ReactSelectionButton>
    </ReactSelectionButtonGroup>
  );
}
Lit (Web Components)
html
<script type="module">
  import "agnosticui-core/selection-button-group";
  import "agnosticui-core/selection-button";

  const group = document.querySelector('ag-selection-button-group');
  group.addEventListener('selection-change', (e) => {
    console.log('Selected:', e.detail.selectedValues);
  });
</script>

<ag-selection-button-group type="radio" name="payment" legend="Select payment method" shape="rounded">
  <ag-selection-button value="card" label="Credit Card">
    Credit Card
  </ag-selection-button>
  <ag-selection-button value="paypal" label="PayPal">
    PayPal
  </ag-selection-button>
</ag-selection-button-group>

Props

SelectionButtonGroup

PropTypeDefaultDescription
type'radio' | 'checkbox''radio'Selection mode
namestring''Input name attribute (required)
legendstring''Accessible group label
legend-hiddenbooleanfalseVisually hide legend
theme'' | 'success' | 'info' | 'warning' | 'error' | 'monochrome'''Theme variant (empty = primary/blue)
size'sm' | 'md' | 'lg''md'Button size
shape'' | 'rounded' | 'capsule'''Button shape (empty = rectangular)
valuestring''Controlled value (radio)
valuesstring[][]Controlled values (checkbox)
disabledbooleanfalseDisable all buttons

SelectionButton

PropTypeDefaultDescription
valuestring''Unique value (required)
labelstring''Accessible label (required)
checkedbooleanfalseSelection state (managed by group)
disabledbooleanfalseDisable this button

Events

selection-change

Fired when selection changes.

typescript
interface SelectionChangeEventDetail {
  value: string;        // Value that triggered the change
  checked: boolean;     // Whether the button is now selected
  selectedValues: string[]; // All currently selected values
}

Themes

The theme prop controls the color scheme for selected buttons:

ThemeDescription
'' (default)Primary blue - uses --ag-primary-* tokens
successGreen - uses --ag-success-* tokens
infoCyan/blue - uses --ag-info-* tokens
warningYellow/orange - uses --ag-warning-* tokens
errorRed - uses --ag-danger-* tokens
monochromeBlack/white - uses --ag-black and inverted tokens
html
<!-- Success theme with capsule shape -->
<ag-selection-button-group type="radio" name="status" theme="success" shape="capsule">
  ...
</ag-selection-button-group>

Sizes

SizeDescription
smSmall - compact height, smaller font
mdMedium (default) - standard size
lgLarge - taller height, larger font

Shapes

ShapeDescription
'' (default)Rectangular with no border radius
roundedModerate border radius
capsuleFully rounded (pill shape)

Styling

CSS Custom Properties

css
/* Group layout */
--ag-selection-button-group-gap: var(--ag-space-2);

/* Button sizing (per size variant) */
/* Size-specific heights and padding are built into the component */

/* Button colors - unchecked */
/* Uses theme tokens (--ag-primary, --ag-success, etc.) for borders and text */

/* Button colors - checked */
/* Filled background using theme tokens */

CSS Parts

SelectionButtonGroup

PartDescription
ag-selection-button-group-fieldsetThe fieldset element
ag-selection-button-group-legendThe legend element
ag-selection-button-group-contentThe content wrapper (flex container)

SelectionButton

PartDescription
ag-selection-button-containerThe outer clickable label
ag-selection-button-controlThe hidden input element
ag-selection-button-indicatorThe selection indicator (circle with dot for radio, circle with checkmark for checkbox)
ag-selection-button-contentThe slotted content wrapper

CSS Parts Example

css
/* Custom gap between buttons */
ag-selection-button-group::part(ag-selection-button-group-content) {
  gap: var(--ag-space-4);
}

/* Custom button styling */
ag-selection-button::part(ag-selection-button-container) {
  font-weight: 600;
}

/* Hide the indicator for a cleaner look */
ag-selection-button::part(ag-selection-button-indicator) {
  display: none;
}

Accessibility

  • Uses <fieldset> and <legend> for proper group semantics
  • Each button has a required label prop for screen readers
  • Keyboard navigation:
    • Arrow keys: Navigate between buttons (selects in radio mode)
    • Space/Enter: Toggle selection
    • Home/End: Jump to first/last button
  • Focus ring visible on keyboard navigation
  • role="radiogroup" for radio mode, role="group" for checkbox mode

Comparison with SelectionCardGroup

FeatureSelectionButtonGroupSelectionCardGroup
Use caseCompact inline optionsRich content cards
Size variantsYes (sm/md/lg)No
Shape variantsYes (rounded/capsule)No
ContentText labelsRich slotted content
LayoutInline flexGrid