diff --git a/packages/gestalt/src/Spinner/VRSpinner.css b/packages/gestalt/src/Spinner/VRSpinner.css
new file mode 100644
index 0000000000..49f5a08fed
--- /dev/null
+++ b/packages/gestalt/src/Spinner/VRSpinner.css
@@ -0,0 +1,94 @@
+.spinner {
+ --g-size: 40px;
+ --g-dot-size: calc(var(--g-size) / 3);
+ --g-dot-space: calc(var(--g-dot-size) * 1.75);
+
+ height: var(--g-size);
+ width: var(--g-size);
+}
+
+.spinnerFrame {
+ animation: spin 1500ms linear infinite;
+ box-sizing: border-box;
+ height: calc(var(--g-dot-space) * sqrt(3) / 2);
+ left: calc(var(--g-dot-size) * 0.625);
+ position: relative;
+ top: calc(var(--g-dot-size) / 2);
+ transform-origin: center calc(var(--g-dot-space) / sqrt(3));
+ width: var(--g-dot-space);
+}
+
+.spinnerFrame > div {
+ animation-composition: add;
+ animation-duration: 800ms, 1.8s;
+ animation-iteration-count: infinite;
+ animation-name: scale, colors;
+ animation-timing-function: linear;
+ border-radius: 50%;
+ height: var(--g-dot-size);
+ position: absolute;
+ width: var(--g-dot-size);
+}
+
+.dot1 {
+ animation-delay: 0s;
+ left: 50%;
+ top: 0;
+ transform: translate3d(-50%, -50%, 0);
+}
+
+.dot2 {
+ animation-delay: 100ms, 0s;
+ bottom: 0;
+ left: 0;
+ transform: translate3d(-50%, 50%, 0);
+}
+
+.dot3 {
+ animation-delay: 200ms, 0s;
+ bottom: 0;
+ right: 0;
+ transform: translate3d(50%, 50%, 0);
+}
+
+.spinner.delay .spinnerFrame > div {
+ animation-delay: 300ms;
+}
+
+.delay {
+ animation-delay: 300ms;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes scale {
+ 50% {
+ transform: scale(0.8);
+ }
+
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes colors {
+ 0% {
+ background-color: var(--comp-spinner-color-background-pink);
+ }
+
+ 33.333% {
+ background-color: var(--comp-spinner-color-background-orange);
+ }
+
+ 66.666% {
+ background-color: var(--comp-spinner-color-background-blue);
+ }
+
+ 100% {
+ background-color: var(--comp-spinner-color-background-pink);
+ }
+}
diff --git a/packages/gestalt/src/Spinner/VRSpinner.tsx b/packages/gestalt/src/Spinner/VRSpinner.tsx
new file mode 100644
index 0000000000..af7c9e081e
--- /dev/null
+++ b/packages/gestalt/src/Spinner/VRSpinner.tsx
@@ -0,0 +1,45 @@
+import classnames from 'classnames';
+import styles from './VRSpinner.css';
+import Box from '../Box';
+import { useDefaultLabelContext } from '../contexts/DefaultLabelProvider';
+
+const SIZE_NAME_TO_PIXEL = {
+ sm: 32,
+ md: 40,
+ lg: 48,
+} as const;
+
+type Props = {
+ accessibilityLabel?: string;
+ delay?: boolean;
+ show: boolean;
+ size?: 'sm' | 'md' | 'lg';
+};
+
+export default function Spinner({ accessibilityLabel, delay = true, show, size = 'md' }: Props) {
+ const { accessibilityLabel: accessibilityLabelDefault } = useDefaultLabelContext('Spinner');
+
+ if (!show) return null;
+
+ return (
+
+
+
+ );
+}
+
+Spinner.displayName = 'Spinner';
diff --git a/packages/gestalt/src/contexts/__snapshots__/ColorSchemeProvider.jsdom.test.tsx.snap b/packages/gestalt/src/contexts/__snapshots__/ColorSchemeProvider.jsdom.test.tsx.snap
index d854dce690..577dd722e2 100644
--- a/packages/gestalt/src/contexts/__snapshots__/ColorSchemeProvider.jsdom.test.tsx.snap
+++ b/packages/gestalt/src/contexts/__snapshots__/ColorSchemeProvider.jsdom.test.tsx.snap
@@ -2879,6 +2879,9 @@ exports[`visual refresh tokens uses visual refresh dark mode theme when specifie
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #007a72;
--color-data-visualization-11: #f76593;
--color-data-visualization-12: #ffc58f;
@@ -3821,6 +3824,9 @@ exports[`visual refresh tokens uses visual refresh light mode theme when specifi
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;
@@ -4761,6 +4767,9 @@ exports[`visual refresh tokens uses visual refresh with ck line height 1`] = `
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;
@@ -5701,6 +5710,9 @@ exports[`visual refresh tokens uses visual refresh with ja line height 1`] = `
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;
@@ -6641,6 +6653,9 @@ exports[`visual refresh tokens uses visual refresh with tall line height 1`] = `
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;
@@ -7581,6 +7596,9 @@ exports[`visual refresh tokens uses visual refresh with th line height 1`] = `
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;
@@ -8521,6 +8539,9 @@ exports[`visual refresh tokens uses visual refresh with vi line height 1`] = `
--sema-motion-opacity-duration-instant: 0ms;
--sema-motion-opacity-easing-default: cubic-bezier(0, 0, 1, 1);
--sema-motion-opacity-easing-instant: cubic-bezier(0, 0, 1, 1);
+ --comp-spinner-color-background-pink: #d452d1;
+ --comp-spinner-color-background-orange: #ff7c36;
+ --comp-spinner-color-background-blue: #24ccb0;
--color-data-visualization-10: #005062;
--color-data-visualization-11: #de2c62;
--color-data-visualization-12: #660e00;