Overview

BeepMultiChipGroup provides a modern, flexible chip-based selection interface inspired by Material Design chip components. It displays a collection of selectable items as rounded "chips" that automatically wrap to fit the available space, making it perfect for tag selection, category filtering, and multi-choice interfaces.

Built on the BeepControl foundation, BeepMultiChipGroup features intelligent auto-sizing, smooth hover animations, comprehensive data binding, title display, and responsive layout behavior. Ideal for forms, filters, dashboards, and any interface requiring an intuitive selection mechanism.

Key Features

🎯 Smart Layout

Auto-wrapping layout with intelligent chip sizing and responsive behavior

✨ Hover Effects

Smooth hover animations with scaling, color transitions, and visual feedback

📝 Title Support

Configurable title display with alignment options and custom styling

🔗 Data Binding

Complete data binding support with SimpleItem collections and change events

🎨 Theme Integration

Full theme support with automatic color application and state management

📱 Responsive Design

Adaptive sizing with auto-height adjustment and container-aware layout

Visual Preview

Basic Chip Group

Select Categories

Technology
Business
Design
Marketing
Finance
Education
Health
Travel

BeepMultiChipGroup with auto-wrapping layout and selection state

Hover and Selection States

Skill Tags

C#
JavaScript
Python
Java
TypeScript
SQL
React
Angular
Vue.js
Node.js

Different chip states: normal, hovered (scaled), and selected

Application Integration

Project Setup

Configure your new project settings

Technology Stack

ASP.NET Core
React
SQL Server
Azure
Docker

Target Platforms

Web
Mobile
Desktop
API

BeepMultiChipGroup integrated in a project setup form

Basic Usage

Simple Chip Group

// Create a multi-chip group
var chipGroup = new BeepMultiChipGroup
{
    TitleText = "Select Categories",
    Location = new Point(20, 20),
    Width = 400
};

// Create chip items
var categories = new BindingList
{
    new SimpleItem { Id = 1, Name = "Technology", Text = "Technology" },
    new SimpleItem { Id = 2, Name = "Business", Text = "Business" },
    new SimpleItem { Id = 3, Name = "Design", Text = "Design" },
    new SimpleItem { Id = 4, Name = "Marketing", Text = "Marketing" },
    new SimpleItem { Id = 5, Name = "Finance", Text = "Finance" },
    new SimpleItem { Id = 6, Name = "Education", Text = "Education" }
};

// Bind data to chip group
chipGroup.ListItems = categories;

// Handle selection changes
chipGroup.SelectedItemChanged += (sender, e) =>
{
    if (e.SelectedItem != null)
    {
        MessageBox.Show($"Selected: {e.SelectedItem.Text}", "Chip Selected");
    }
};

// Add to form
this.Controls.Add(chipGroup);

Programmatic Selection

// Set initial selection
chipGroup.SelectedItem = categories.FirstOrDefault(c => c.Name == "Technology");

// Or set by index
chipGroup.SelectedIndex = 1;

// Or set by GUID ID
chipGroup.SetValue("specific-guid-here");

// Get current selection
var selected = chipGroup.SelectedItem;
if (selected != null)
{
  //  Console.WriteLine($"Current selection: {selected.Text}");
}

// Clear selection
chipGroup.ClearValue();

Dynamic Chip Management

// Add new chips dynamically
var newChip = new SimpleItem 
{ 
    Id = categories.Count + 1, 
    Name = "Science", 
    Text = "Science" 
};
chipGroup.ListItems.Add(newChip);

// Remove chips
var chipToRemove = chipGroup.ListItems.FirstOrDefault(c => c.Name == "Finance");
if (chipToRemove != null)
{
    chipGroup.ListItems.Remove(chipToRemove);
}

// Update chip text
var techChip = chipGroup.ListItems.FirstOrDefault(c => c.Name == "Technology");
if (techChip != null)
{
    techChip.Text = "Tech & Innovation";
    // The control will automatically refresh
}

// Bulk update
var newCategories = new BindingList
{
    new SimpleItem { Id = 1, Name = "Frontend", Text = "Frontend Development" },
    new SimpleItem { Id = 2, Name = "Backend", Text = "Backend Development" },
    new SimpleItem { Id = 3, Name = "DevOps", Text = "DevOps & Infrastructure" },
    new SimpleItem { Id = 4, Name = "Mobile", Text = "Mobile Development" }
};
chipGroup.ListItems = newCategories;

Properties

Data Properties

Property Type Default Description
ListItems BindingList<SimpleItem> Empty list Collection of chip items to display
SelectedItem SimpleItem null Currently selected chip item
SelectedIndex int -1 Index of the currently selected chip

Title Properties

Property Type Default Description
TitleText string "Multi-Select Chip Group" Title text displayed above the chips
TitleFont Font Segoe UI, 12pt, Bold Font used for the title text
TitleColor Color Black (theme-based) Color of the title text
TitleAlignment ContentAlignment TopLeft Alignment of the title text

Layout Properties

Property Type Default Description
AutoSize bool true Automatically size control to fit all chips
AutoScroll bool false (disabled) Scrolling is disabled for chip groups

Internal Constants

Property Value Description
Chip Padding 5 pixels Spacing between individual chips
Chip Height 30 pixels Fixed height for all chips
Corner Radius 15 pixels Rounded corner radius for chips
Title Height 30 pixels Height reserved for title display

Events

Event Event Args Description
SelectedItemChanged SelectedItemChangedEventArgs Fired when the selected chip changes

SelectedItemChangedEventArgs Properties

Property Type Description
SelectedItem SimpleItem The newly selected chip item (null if cleared)

Examples

Product Category Filter

public class ProductFilterForm : Form
{
    private BeepMultiChipGroup categoryChips;
    private BeepMultiChipGroup brandChips;
    private BeepMultiChipGroup priceRangeChips;
    private ListView productList;
    private List allProducts;
    private List filteredProducts;

    public ProductFilterForm()
    {
        SetupInterface();
        LoadData();
    }

    private void SetupInterface()
    {
        this.Size = new Size(800, 600);
        this.Text = "Product Filter";

        var mainPanel = new Panel { Dock = DockStyle.Fill };
        var filterPanel = new Panel { Dock = DockStyle.Top, Height = 250, Padding = new Padding(20) };
        
        // Category filter
        categoryChips = new BeepMultiChipGroup
        {
            TitleText = "Product Categories",
            Location = new Point(0, 0),
            Width = 700,
            Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
        };

        var categories = new BindingList
        {
            new SimpleItem { Id = 1, Name = "electronics", Text = "Electronics" },
            new SimpleItem { Id = 2, Name = "clothing", Text = "Clothing" },
            new SimpleItem { Id = 3, Name = "books", Text = "Books" },
            new SimpleItem { Id = 4, Name = "home", Text = "Home & Garden" },
            new SimpleItem { Id = 5, Name = "sports", Text = "Sports & Outdoors" },
            new SimpleItem { Id = 6, Name = "toys", Text = "Toys & Games" }
        };
        categoryChips.ListItems = categories;
        categoryChips.SelectedItemChanged += CategoryChips_SelectedItemChanged;

        // Brand filter
        brandChips = new BeepMultiChipGroup
        {
            TitleText = "Brands",
            Location = new Point(0, 80),
            Width = 700,
            Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
        };

        var brands = new BindingList
        {
            new SimpleItem { Id = 1, Name = "apple", Text = "Apple" },
            new SimpleItem { Id = 2, Name = "samsung", Text = "Samsung" },
            new SimpleItem { Id = 3, Name = "nike", Text = "Nike" },
            new SimpleItem { Id = 4, Name = "adidas", Text = "Adidas" },
            new SimpleItem { Id = 5, Name = "sony", Text = "Sony" },
            new SimpleItem { Id = 6, Name = "microsoft", Text = "Microsoft" }
        };
        brandChips.ListItems = brands;
        brandChips.SelectedItemChanged += BrandChips_SelectedItemChanged;

        // Price range filter
        priceRangeChips = new BeepMultiChipGroup
        {
            TitleText = "Price Range",
            Location = new Point(0, 160),
            Width = 700,
            Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
        };

        var priceRanges = new BindingList
        {
            new SimpleItem { Id = 1, Name = "0-25", Text = "$0 - $25" },
            new SimpleItem { Id = 2, Name = "25-50", Text = "$25 - $50" },
            new SimpleItem { Id = 3, Name = "50-100", Text = "$50 - $100" },
            new SimpleItem { Id = 4, Name = "100-250", Text = "$100 - $250" },
            new SimpleItem { Id = 5, Name = "250+", Text = "$250+" }
        };
        priceRangeChips.ListItems = priceRanges;
        priceRangeChips.SelectedItemChanged += PriceRangeChips_SelectedItemChanged;

        filterPanel.Controls.AddRange(new Control[] 
        { 
            categoryChips, brandChips, priceRangeChips 
        });

        // Product list
        productList = new ListView
        {
            Dock = DockStyle.Fill,
            View = View.Details,
            FullRowSelect = true,
            GridLines = true
        };

        productList.Columns.AddRange(new[]
        {
            new ColumnHeader { Text = "Name", Width = 200 },
            new ColumnHeader { Text = "Category", Width = 120 },
            new ColumnHeader { Text = "Brand", Width = 100 },
            new ColumnHeader { Text = "Price", Width = 80 },
            new ColumnHeader { Text = "Rating", Width = 80 }
        });

        mainPanel.Controls.AddRange(new Control[] { productList, filterPanel });
        this.Controls.Add(mainPanel);
    }

    private void CategoryChips_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
    {
        ApplyFilters();
    }

    private void BrandChips_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
    {
        ApplyFilters();
    }

    private void PriceRangeChips_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
    {
        ApplyFilters();
    }

    private void ApplyFilters()
    {
        filteredProducts = allProducts.Where(product =>
        {
            // Category filter
            if (categoryChips.SelectedItem != null)
            {
                var selectedCategory = categoryChips.SelectedItem.Name;
                if (!product.Category.ToLower().Contains(selectedCategory))
                    return false;
            }

            // Brand filter
            if (brandChips.SelectedItem != null)
            {
                var selectedBrand = brandChips.SelectedItem.Name;
                if (!product.Brand.ToLower().Contains(selectedBrand))
                    return false;
            }

            // Price range filter
            if (priceRangeChips.SelectedItem != null)
            {
                var selectedRange = priceRangeChips.SelectedItem.Name;
                if (!IsInPriceRange(product.Price, selectedRange))
                    return false;
            }

            return true;
        }).ToList();

        UpdateProductList();
    }

    private bool IsInPriceRange(decimal price, string range)
    {
        return range switch
        {
            "0-25" => price >= 0 && price <= 25,
            "25-50" => price > 25 && price <= 50,
            "50-100" => price > 50 && price <= 100,
            "100-250" => price > 100 && price <= 250,
            "250+" => price > 250,
            _ => true
        };
    }

    private void UpdateProductList()
    {
        productList.Items.Clear();
        foreach (var product in filteredProducts)
        {
            var item = new ListViewItem(new[]
            {
                product.Name,
                product.Category,
                product.Brand,
                product.Price.ToString("C"),
                product.Rating.ToString("F1")
            });
            productList.Items.Add(item);
        }
    }

    private void LoadData()
    {
        // Sample product data
        allProducts = new List
        {
            new Product { Name = "iPhone 14", Category = "Electronics", Brand = "Apple", Price = 999, Rating = 4.8m },
            new Product { Name = "Galaxy S23", Category = "Electronics", Brand = "Samsung", Price = 899, Rating = 4.6m },
            new Product { Name = "Air Max 90", Category = "Shoes", Brand = "Nike", Price = 120, Rating = 4.4m },
            new Product { Name = "Ultraboost 22", Category = "Shoes", Brand = "Adidas", Price = 180, Rating = 4.5m },
            new Product { Name = "WH-1000XM4", Category = "Electronics", Brand = "Sony", Price = 279, Rating = 4.7m },
            new Product { Name = "Surface Laptop", Category = "Electronics", Brand = "Microsoft", Price = 1299, Rating = 4.3m }
        };

        filteredProducts = allProducts.ToList();
        UpdateProductList();
    }
}

public class Product
{
    public string Name { get; set; }
    public string Category { get; set; }
    public string Brand { get; set; }
    public decimal Price { get; set; }
    public decimal Rating { get; set; }
}

Skill Selection Form

public class SkillSelectionControl : UserControl
{
    private BeepMultiChipGroup programmingChips;
    private BeepMultiChipGroup frameworkChips;
    private BeepMultiChipGroup databaseChips;
    private BeepMultiChipGroup cloudChips;
    private List selectedSkills = new List();

    public event EventHandler SkillSelectionChanged;

    public SkillSelectionControl()
    {
        SetupChipGroups();
        LoadSkillData();
    }

    private void SetupChipGroups()
    {
        this.Size = new Size(600, 400);
        this.AutoScroll = true;

        // Programming Languages
        programmingChips = CreateChipGroup("Programming Languages", new Point(20, 20));
        
        // Frameworks
        frameworkChips = CreateChipGroup("Frameworks & Libraries", new Point(20, 120));
        
        // Databases
        databaseChips = CreateChipGroup("Databases", new Point(20, 220));
        
        // Cloud Platforms
        cloudChips = CreateChipGroup("Cloud Platforms", new Point(20, 320));

        this.Controls.AddRange(new Control[] 
        { 
            programmingChips, frameworkChips, databaseChips, cloudChips 
        });
    }

    private BeepMultiChipGroup CreateChipGroup(string title, Point location)
    {
        var chipGroup = new BeepMultiChipGroup
        {
            TitleText = title,
            Location = location,
            Width = 550,
            Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
        };

        chipGroup.SelectedItemChanged += ChipGroup_SelectedItemChanged;
        return chipGroup;
    }

    private void LoadSkillData()
    {
        // Programming languages
        var programmingLanguages = new BindingList
        {
            new SimpleItem { Id = 1, Name = "csharp", Text = "C#" },
            new SimpleItem { Id = 2, Name = "javascript", Text = "JavaScript" },
            new SimpleItem { Id = 3, Name = "python", Text = "Python" },
            new SimpleItem { Id = 4, Name = "java", Text = "Java" },
            new SimpleItem { Id = 5, Name = "typescript", Text = "TypeScript" },
            new SimpleItem { Id = 6, Name = "go", Text = "Go" },
            new SimpleItem { Id = 7, Name = "rust", Text = "Rust" },
            new SimpleItem { Id = 8, Name = "kotlin", Text = "Kotlin" }
        };
        programmingChips.ListItems = programmingLanguages;

        // Frameworks
        var frameworks = new BindingList
        {
            new SimpleItem { Id = 1, Name = "react", Text = "React" },
            new SimpleItem { Id = 2, Name = "angular", Text = "Angular" },
            new SimpleItem { Id = 3, Name = "vue", Text = "Vue.js" },
            new SimpleItem { Id = 4, Name = "aspnet", Text = "ASP.NET Core" },
            new SimpleItem { Id = 5, Name = "django", Text = "Django" },
            new SimpleItem { Id = 6, Name = "spring", Text = "Spring Boot" },
            new SimpleItem { Id = 7, Name = "express", Text = "Express.js" },
            new SimpleItem { Id = 8, Name = "fastapi", Text = "FastAPI" }
        };
        frameworkChips.ListItems = frameworks;

        // Databases
        var databases = new BindingList
        {
            new SimpleItem { Id = 1, Name = "sqlserver", Text = "SQL Server" },
            new SimpleItem { Id = 2, Name = "mysql", Text = "MySQL" },
            new SimpleItem { Id = 3, Name = "postgresql", Text = "PostgreSQL" },
            new SimpleItem { Id = 4, Name = "mongodb", Text = "MongoDB" },
            new SimpleItem { Id = 5, Name = "redis", Text = "Redis" },
            new SimpleItem { Id = 6, Name = "sqlite", Text = "SQLite" },
            new SimpleItem { Id = 7, Name = "oracle", Text = "Oracle" }
        };
        databaseChips.ListItems = databases;

        // Cloud platforms
        var cloudPlatforms = new BindingList
        {
            new SimpleItem { Id = 1, Name = "azure", Text = "Microsoft Azure" },
            new SimpleItem { Id = 2, Name = "aws", Text = "Amazon AWS" },
            new SimpleItem { Id = 3, Name = "gcp", Text = "Google Cloud" },
            new SimpleItem { Id = 4, Name = "docker", Text = "Docker" },
            new SimpleItem { Id = 5, Name = "kubernetes", Text = "Kubernetes" },
            new SimpleItem { Id = 6, Name = "digitalocean", Text = "DigitalOcean" }
        };
        cloudChips.ListItems = cloudPlatforms;
    }

    private void ChipGroup_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
    {
        UpdateSelectedSkills();
        OnSkillSelectionChanged();
    }

    private void UpdateSelectedSkills()
    {
        selectedSkills.Clear();

        // Collect selected skills from all chip groups
        if (programmingChips.SelectedItem != null)
            selectedSkills.Add($"Programming: {programmingChips.SelectedItem.Text}");

        if (frameworkChips.SelectedItem != null)
            selectedSkills.Add($"Framework: {frameworkChips.SelectedItem.Text}");

        if (databaseChips.SelectedItem != null)
            selectedSkills.Add($"Database: {databaseChips.SelectedItem.Text}");

        if (cloudChips.SelectedItem != null)
            selectedSkills.Add($"Cloud: {cloudChips.SelectedItem.Text}");
    }

    private void OnSkillSelectionChanged()
    {
        SkillSelectionChanged?.Invoke(this, new SkillSelectionChangedEventArgs
        {
            SelectedSkills = selectedSkills.ToList(),
            ProgrammingLanguage = programmingChips.SelectedItem?.Text,
            Framework = frameworkChips.SelectedItem?.Text,
            Database = databaseChips.SelectedItem?.Text,
            CloudPlatform = cloudChips.SelectedItem?.Text
        });
    }

    public void ClearAllSelections()
    {
        programmingChips.ClearValue();
        frameworkChips.ClearValue();
        databaseChips.ClearValue();
        cloudChips.ClearValue();
    }

    public void SetSelections(string programming, string framework, string database, string cloud)
    {
        if (!string.IsNullOrEmpty(programming))
        {
            var progItem = programmingChips.ListItems.FirstOrDefault(i => i.Text == programming);
            if (progItem != null) programmingChips.SelectedItem = progItem;
        }

        if (!string.IsNullOrEmpty(framework))
        {
            var fwItem = frameworkChips.ListItems.FirstOrDefault(i => i.Text == framework);
            if (fwItem != null) frameworkChips.SelectedItem = fwItem;
        }

        if (!string.IsNullOrEmpty(database))
        {
            var dbItem = databaseChips.ListItems.FirstOrDefault(i => i.Text == database);
            if (dbItem != null) databaseChips.SelectedItem = dbItem;
        }

        if (!string.IsNullOrEmpty(cloud))
        {
            var cloudItem = cloudChips.ListItems.FirstOrDefault(i => i.Text == cloud);
            if (cloudItem != null) cloudChips.SelectedItem = cloudItem;
        }
    }
}

public class SkillSelectionChangedEventArgs : EventArgs
{
    public List SelectedSkills { get; set; }
    public string ProgrammingLanguage { get; set; }
    public string Framework { get; set; }
    public string Database { get; set; }
    public string CloudPlatform { get; set; }
}

Theming

BeepMultiChipGroup provides comprehensive theming with automatic application to all chips and states:

Theme Application

var chipGroup = new BeepMultiChipGroup
{
    Theme = "DarkTheme",
    TitleText = "Select Options"
};

// Theme automatically applies to:
// - Chip background colors
// - Chip text colors
// - Hover state colors
// - Selected state colors
// - Title text color
// - Border colors

// Manual theme refresh
chipGroup.ApplyTheme();

Chip Group Theme Properties

  • ButtonBackColor - Normal chip background
  • ButtonForeColor - Normal chip text color
  • ButtonHoverBackColor - Chip hover background
  • ButtonHoverForeColor - Chip hover text color
  • ButtonSelectedForeColor - Selected chip colors
  • CardTitleForeColor - Title text color
  • BorderColor - Chip borders
  • HoverLinkColor - Hover border colors

Custom Chip Styling

// Apply theme first
chipGroup.ApplyTheme();

// Customize title appearance
chipGroup.TitleColor = Color.FromArgb(52, 73, 94);
chipGroup.TitleFont = new Font("Segoe UI", 14, FontStyle.Bold);
chipGroup.TitleAlignment = ContentAlignment.TopCenter;

// The control handles individual chip styling automatically
// based on the current theme and interaction states

Best Practices

🎯 Chip Design

  • Concise labels: Keep chip text short and descriptive
  • Logical grouping: Group related chips in separate chip groups
  • Consistent sizing: Let the control handle automatic sizing for consistency
  • Clear titles: Use descriptive titles to explain chip purpose

📱 Layout Considerations

  • Width allocation: Provide adequate width for chip wrapping
  • AutoSize usage: Enable AutoSize for dynamic height adjustment
  • Spacing management: Use proper margins between chip groups
  • Responsive design: Consider how chips wrap on different screen sizes

🔗 Data Management

  • SimpleItem usage: Properly populate SimpleItem properties (Id, Name, Text)
  • Change detection: Use SelectedItemChanged event for responsive updates
  • State preservation: Store selections appropriately for form persistence
  • Dynamic updates: Use BindingList for automatic UI updates

✨ User Experience

  • Visual feedback: Leverage hover and selection state animations
  • Single selection: Remember this is a single-selection control
  • Clear indication: Ensure selected state is visually distinct
  • Accessibility: Ensure adequate color contrast for all states
💡 Layout Tip

Set a reasonable width (400-600px) to allow proper chip wrapping while maintaining readability. Too narrow causes excessive wrapping, too wide wastes space.

✅ Best Practice

Use descriptive chip text that clearly indicates what selecting the chip will accomplish - avoid ambiguous labels like "Option 1" or "Choice A".

⚠️ Selection Warning

BeepMultiChipGroup supports single selection only. For multi-selection scenarios, consider using multiple chip groups or a different control type.