diff --git a/webui/src/common/components/LoadingSpinner/LoadingSpinner.jsx b/webui/src/common/components/LoadingSpinner/LoadingSpinner.jsx
new file mode 100644
index 0000000..5dece08
--- /dev/null
+++ b/webui/src/common/components/LoadingSpinner/LoadingSpinner.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import './styles.sass';
+
+export const LoadingSpinner = ({
+ size = 'md',
+ className = '',
+ text,
+ centered = false
+}) => {
+ const containerClasses = [
+ 'loading-container',
+ centered && 'loading-container--centered',
+ className
+ ].filter(Boolean).join(' ');
+
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/webui/src/common/components/LoadingSpinner/index.js b/webui/src/common/components/LoadingSpinner/index.js
new file mode 100644
index 0000000..a8fee35
--- /dev/null
+++ b/webui/src/common/components/LoadingSpinner/index.js
@@ -0,0 +1 @@
+export { LoadingSpinner as default } from './LoadingSpinner.jsx';
\ No newline at end of file
diff --git a/webui/src/common/components/LoadingSpinner/styles.sass b/webui/src/common/components/LoadingSpinner/styles.sass
new file mode 100644
index 0000000..4624022
--- /dev/null
+++ b/webui/src/common/components/LoadingSpinner/styles.sass
@@ -0,0 +1,40 @@
+.loading-container
+ display: flex
+ flex-direction: column
+ align-items: center
+ gap: 1rem
+
+ &--centered
+ justify-content: center
+ padding: 3rem 2rem
+
+.loading-spinner
+ border-radius: 50%
+ border-style: solid
+ border-color: var(--bg-elev)
+ border-top-color: var(--accent)
+ animation: spin 1s linear infinite
+
+ &--sm
+ width: 16px
+ height: 16px
+ border-width: 2px
+
+ &--md
+ width: 32px
+ height: 32px
+ border-width: 3px
+
+ &--lg
+ width: 48px
+ height: 48px
+ border-width: 4px
+
+.loading-text
+ color: var(--text-dim)
+ font-size: 0.95rem
+ margin: 0
+
+@keyframes spin
+ to
+ transform: rotate(360deg)
\ No newline at end of file