diff --git a/EXHAUSTIVE_TODO_LIST.md b/EXHAUSTIVE_TODO_LIST.md
index 4c3062f5a..f36e54bb2 100644
--- a/EXHAUSTIVE_TODO_LIST.md
+++ b/EXHAUSTIVE_TODO_LIST.md
@@ -2942,11 +2942,18 @@ Critical path dependencies:
- **Result**: All high and medium priority mutation buttons now have loading states. Low priority buttons (auto-triggered notifications) can be enhanced incrementally if needed.
- **Rollback**: Remove loading states
-- [ ] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
+- [x] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
- **Scope**: `apps/web/src/components/ui/Spinner.tsx` (create) - Reusable spinner component
- - **Dependencies**: None
+ - **Dependencies**: None ✅
- **Risk**: LOW 🔒
- - **Validation**: Spinner component works
+ - **Validation**: ✅ Spinner component created:
+ - **File**: Created `apps/web/src/components/ui/Spinner.tsx`
+ - **Component**: Simple, reusable inline spinner component
+ - **Features**: Size variants (sm, md, lg), color variants (default, muted, white, current), accessibility (aria-label, role="status")
+ - **Design**: Uses Kodo design system colors (kodo-cyan by default), wraps Loader2 from lucide-react
+ - **Purpose**: Optimized for inline use in buttons and UI elements (different from LoadingSpinner which is for full-page states)
+ - **Pattern**: Follows existing component patterns with TypeScript interfaces and JSDoc documentation
+ - **Result**: Reusable spinner component ready for use in loading states
- **Rollback**: Delete component
- [ ] **Action 8.3.1.5**: Use Spinner in loading states
diff --git a/apps/web/src/components/ui/Spinner.tsx b/apps/web/src/components/ui/Spinner.tsx
new file mode 100644
index 000000000..2dd68c211
--- /dev/null
+++ b/apps/web/src/components/ui/Spinner.tsx
@@ -0,0 +1,108 @@
+import { Loader2 } from 'lucide-react';
+import { cn } from '@/lib/utils';
+
+/**
+ * SpinnerProps - Propriétés du composant Spinner
+ *
+ * @interface SpinnerProps
+ */
+export interface SpinnerProps {
+ /**
+ * Taille du spinner
+ *
+ * - `sm`: Petit (h-4 w-4) - pour les boutons et éléments compacts
+ * - `md`: Moyen (h-5 w-5) - par défaut
+ * - `lg`: Grand (h-6 w-6) - pour les éléments plus grands
+ *
+ * @default 'md'
+ */
+ size?: 'sm' | 'md' | 'lg';
+
+ /**
+ * Couleur du spinner
+ *
+ * - `default`: Couleur par défaut (kodo-cyan pour le thème Kodo)
+ * - `muted`: Couleur atténuée (text-muted-foreground)
+ * - `white`: Blanc
+ * - `current`: Utilise la couleur du texte parent
+ *
+ * @default 'default'
+ */
+ variant?: 'default' | 'muted' | 'white' | 'current';
+
+ /**
+ * Classes CSS personnalisées
+ */
+ className?: string;
+
+ /**
+ * Label d'accessibilité
+ *
+ * @default 'Chargement en cours'
+ */
+ 'aria-label'?: string;
+}
+
+/**
+ * Spinner - Composant de spinner réutilisable pour les états de chargement inline
+ *
+ * Composant de spinner optimisé pour l'utilisation inline dans les boutons,
+ * formulaires et autres éléments UI. Utilise le design system Kodo.
+ *
+ * Différences avec LoadingSpinner:
+ * - LoadingSpinner: Pour les états de chargement de page complète avec conteneur
+ * - Spinner: Pour les spinners inline dans les boutons et éléments UI
+ *
+ * @example
+ * ```tsx
+ * // Spinner simple dans un bouton
+ *
+ *
+ * // Spinner avec couleur personnalisée
+ *
+ *
+ * // Spinner avec classes personnalisées
+ *
+ * ```
+ *
+ * @component
+ * @param {SpinnerProps} props - Propriétés du composant
+ * @returns {JSX.Element} Spinner animé
+ */
+export function Spinner({
+ size = 'md',
+ variant = 'default',
+ className,
+ 'aria-label': ariaLabel = 'Chargement en cours',
+}: SpinnerProps) {
+ const sizeClasses = {
+ sm: 'h-4 w-4',
+ md: 'h-5 w-5',
+ lg: 'h-6 w-6',
+ };
+
+ const variantClasses = {
+ default: 'text-kodo-cyan',
+ muted: 'text-muted-foreground',
+ white: 'text-white',
+ current: 'text-current',
+ };
+
+ return (
+ <>
+
+ {ariaLabel}
+ >
+ );
+}