diff --git a/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.css b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.css new file mode 100644 index 0000000000..6bdc3c5d8b --- /dev/null +++ b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.css @@ -0,0 +1,116 @@ +/* + EaseMotion CSS - Filter Chip Group + Provides semantic layout styling and the Smooth Select Transitions. +*/ + +.ease-chip-group { + display: flex; + flex-wrap: wrap; + gap: 12px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; +} + +/* Base Chip Styling */ +.ease-filter-chip { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 16px; + border-radius: 9999px; /* Pill shape */ + border: 1px solid #e2e8f0; + background-color: #f8fafc; + color: #475569; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + outline: none; + + /* Smooth hardware-accelerated transitions for colors and box-shadow */ + transition: + background-color 0.25s cubic-bezier(0.4, 0, 0.2, 1), + border-color 0.25s cubic-bezier(0.4, 0, 0.2, 1), + color 0.25s cubic-bezier(0.4, 0, 0.2, 1), + box-shadow 0.2s ease, + transform 0.1s ease; /* For active click state */ +} + +/* Hover and Focus States */ +.ease-filter-chip:hover { + background-color: #f1f5f9; + border-color: #cbd5e1; + color: #0f172a; +} + +.ease-filter-chip:focus-visible { + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); + border-color: #3b82f6; +} + +/* Active Click state for tactile feedback */ +.ease-filter-chip:active { + transform: scale(0.96); +} + +/* Icon Wrapper for width transitions */ +.ease-chip-icon-wrapper { + display: flex; + align-items: center; + justify-content: center; + + /* Initial state: Hidden (width 0, margin 0, opacity 0) */ + width: 0; + margin-right: 0; + opacity: 0; + transform: scale(0.5); + + /* Smoothly animate width and opacity */ + transition: + width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), + margin-right 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), + opacity 0.2s ease-in-out, + transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.ease-chip-check-icon { + width: 16px; + height: 16px; + color: #ffffff; +} + +/* + ======================================== + SELECTED STATE + ======================================== +*/ +.ease-chip-selected { + background-color: #3b82f6; + border-color: #3b82f6; + color: #ffffff; +} + +.ease-chip-selected:hover { + background-color: #2563eb; + border-color: #2563eb; + color: #ffffff; +} + +/* When selected, expand the wrapper and fade/scale in the check icon */ +.ease-chip-selected .ease-chip-icon-wrapper { + width: 16px; + margin-right: 6px; /* Space between icon and label */ + opacity: 1; + transform: scale(1); +} + +/* Accessibility: Respect Reduced Motion */ +@media (prefers-reduced-motion: reduce) { + .ease-filter-chip { + transition: none; + } + .ease-filter-chip:active { + transform: none; + } + .ease-chip-icon-wrapper { + transition: none; + } +} diff --git a/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.jsx b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.jsx new file mode 100644 index 0000000000..4394b25c94 --- /dev/null +++ b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/FilterChipGroup.jsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import './FilterChipGroup.css'; + +/** + * Filter Chip Group with Smooth Select Transitions + * + * A reusable React component that renders a group of interactive + * filter chips. It handles multi-selection state and utilizes + * pure CSS transitions to smoothly animate background colors, + * text colors, and the entrance/exit of a checkmark icon. + * + * @param {Array} filters - Array of filter objects { id: string, label: string } + * @param {Array} initialSelected - Array of filter IDs that are selected by default + * @param {function} onChange - Callback returning the array of currently selected IDs + */ +const FilterChipGroup = ({ + filters = [ + { id: 'f1', label: 'All' }, + { id: 'f2', label: 'Design' }, + { id: 'f3', label: 'Development' }, + { id: 'f4', label: 'Marketing' }, + { id: 'f5', label: 'Product' } + ], + initialSelected = ['f1'], + onChange = () => {} +}) => { + const [selectedIds, setSelectedIds] = useState(initialSelected); + + const toggleFilter = (id) => { + let newSelection; + if (selectedIds.includes(id)) { + // Deselect + newSelection = selectedIds.filter((selectedId) => selectedId !== id); + } else { + // Select + newSelection = [...selectedIds, id]; + } + setSelectedIds(newSelection); + if (onChange) { + onChange(newSelection); + } + }; + + return ( +
+ {filters.map((filter) => { + const isSelected = selectedIds.includes(filter.id); + + return ( + + ); + })} +
+ ); +}; + +export default FilterChipGroup; diff --git a/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/README.md b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/README.md new file mode 100644 index 0000000000..3fa98f7b41 --- /dev/null +++ b/submissions/react/react-filter-chip-group-with-smooth-select-transitions-realtushartyagi-28028/README.md @@ -0,0 +1,63 @@ +# React Filter Chip Group with Smooth Select Transitions + +A highly interactive, accessible React component that renders a group of multi-selectable filter chips (pill tags). When a user toggles a chip, it utilizes smooth CSS transitions to gracefully animate background colors and seamlessly expand a checkmark icon using a bouncy cubic-bezier curve. + +## Files +- `FilterChipGroup.jsx` – The core React component that handles the multi-selection state array and renders the SVG checkmarks. +- `FilterChipGroup.css` – The stylesheet that powers the pill layout, hover states, and the 60fps width/opacity transitions. + +## How it works +1. **State Management**: The component tracks an array of `selectedIds`. Clicking a chip toggles its ID in and out of the array. +2. **Dynamic Class Switching**: Selected chips receive the `.ease-chip-selected` class, which triggers the visual change. +3. **The Entrance Animation**: The checkmark icon is wrapped in `.ease-chip-icon-wrapper` which defaults to `width: 0` and `opacity: 0`. When `.ease-chip-selected` is applied to the parent, CSS immediately transitions the wrapper's `width` to `16px` and `opacity` to `1` using a spring-like `cubic-bezier` timing function. This creates the illusion that the text smoothly pushes aside to make room for the checkmark. + +## Installation & Usage + +1. Copy both `FilterChipGroup.jsx` and `FilterChipGroup.css` into your React project. +2. Import the component and pass it an array of filter options. + +```jsx +import React, { useState } from 'react'; +import FilterChipGroup from './components/FilterChipGroup'; + +const App = () => { + const [activeFilters, setActiveFilters] = useState(['tag-react']); + + const blogTags = [ + { id: 'tag-react', label: 'React' }, + { id: 'tag-css', label: 'CSS Animations' }, + { id: 'tag-ui', label: 'UI Design' }, + { id: 'tag-a11y', label: 'Accessibility' } + ]; + + return ( +
+ setActiveFilters(newSelection)} + /> + +

+ Active Filters: {activeFilters.join(', ')} +

+
+ ); +}; + +export default App; +``` + +## Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `filters` | `Array` | *(Demo items)* | Array of options to render. Shape: `{ id: string, label: string }`. | +| `initialSelected` | `Array` | `['f1']` | Array of `id` strings that should be active on initial mount. | +| `onChange` | `function` | `() => {}` | Callback fired whenever the selection changes. Receives the updated array of selected IDs. | + +## Accessibility (prefers-reduced-motion) +The component uses native `