From 31bd909a1c939359dafe45ff1847a92b8c2d5aaf Mon Sep 17 00:00:00 2001 From: paanSinghCoder Date: Fri, 20 Mar 2026 16:53:40 +0530 Subject: [PATCH 1/4] style: prefer reduced motion --- .../src/content/docs/components/accordion/index.mdx | 1 + .../src/content/docs/components/alert-dialog/index.mdx | 1 + apps/www/src/content/docs/components/button/index.mdx | 1 + .../src/content/docs/components/collapsible/index.mdx | 1 + apps/www/src/content/docs/components/dialog/index.mdx | 1 + apps/www/src/content/docs/components/drawer/index.mdx | 1 + apps/www/src/content/docs/components/link/index.mdx | 1 + apps/www/src/content/docs/components/popover/index.mdx | 1 + .../www/src/content/docs/components/skeleton/index.mdx | 2 +- apps/www/src/content/docs/components/spinner/index.mdx | 1 + apps/www/src/content/docs/components/toast/index.mdx | 1 + apps/www/src/content/docs/components/tooltip/index.mdx | 4 ++++ .../raystack/components/accordion/accordion.module.css | 10 ++++++++++ packages/raystack/components/button/button.module.css | 7 +++++++ .../components/collapsible/collapsible.module.css | 6 ++++++ packages/raystack/components/link/link.module.css | 6 ++++++ .../raystack/components/popover/popover.module.css | 6 ++++++ .../raystack/components/skeleton/skeleton.module.css | 7 +++++++ .../raystack/components/spinner/spinner.module.css | 7 +++++++ .../raystack/components/tooltip/tooltip.module.css | 6 ++++++ 20 files changed, 70 insertions(+), 1 deletion(-) diff --git a/apps/www/src/content/docs/components/accordion/index.mdx b/apps/www/src/content/docs/components/accordion/index.mdx index d052c8ba6..a56fa334e 100644 --- a/apps/www/src/content/docs/components/accordion/index.mdx +++ b/apps/www/src/content/docs/components/accordion/index.mdx @@ -90,3 +90,4 @@ The accordion content can contain any React elements, allowing for rich layouts - Trigger elements use `aria-expanded` to indicate open/closed state - Supports keyboard navigation with Enter and Space to toggle items - Content panels use `aria-controls` and `aria-labelledby` for association +- Respects `prefers-reduced-motion: reduce` by disabling the icon rotation transition and content height transition diff --git a/apps/www/src/content/docs/components/alert-dialog/index.mdx b/apps/www/src/content/docs/components/alert-dialog/index.mdx index 020854f7e..f7ab58848 100644 --- a/apps/www/src/content/docs/components/alert-dialog/index.mdx +++ b/apps/www/src/content/docs/components/alert-dialog/index.mdx @@ -121,3 +121,4 @@ You can nest alert dialogs for multi-step confirmation flows. When a nested aler - Uses `aria-label` or `aria-labelledby` to identify the dialog - Uses `aria-describedby` to provide additional context - Focus is trapped within the alert dialog while open +- Respects `prefers-reduced-motion: reduce` by disabling dialog overlay/panel transitions diff --git a/apps/www/src/content/docs/components/button/index.mdx b/apps/www/src/content/docs/components/button/index.mdx index c49f24a0e..8b3fab898 100644 --- a/apps/www/src/content/docs/components/button/index.mdx +++ b/apps/www/src/content/docs/components/button/index.mdx @@ -75,3 +75,4 @@ The button component accepts optional leading and/or trailing icons. - Supports keyboard activation with Enter and Space keys - Disabled state is communicated via `aria-disabled` attribute - Loading state prevents interaction and announces status to screen readers +- Respects `prefers-reduced-motion: reduce` by disabling the button loader rotation animation diff --git a/apps/www/src/content/docs/components/collapsible/index.mdx b/apps/www/src/content/docs/components/collapsible/index.mdx index 540f7abbe..dd14c49a0 100644 --- a/apps/www/src/content/docs/components/collapsible/index.mdx +++ b/apps/www/src/content/docs/components/collapsible/index.mdx @@ -72,3 +72,4 @@ The collapsible can be disabled to prevent user interaction. - The Trigger uses `aria-expanded` to indicate the open/closed state of the panel. - Supports keyboard interaction with Enter and Space to toggle the panel. - The Panel is automatically associated with the Trigger via `aria-controls`. +- Respects `prefers-reduced-motion: reduce` by disabling the panel height transition diff --git a/apps/www/src/content/docs/components/dialog/index.mdx b/apps/www/src/content/docs/components/dialog/index.mdx index 86e5d37ca..28bb0acfe 100644 --- a/apps/www/src/content/docs/components/dialog/index.mdx +++ b/apps/www/src/content/docs/components/dialog/index.mdx @@ -123,3 +123,4 @@ You can nest dialogs within one another. When a nested dialog opens, the parent - Dialog has `role="dialog"` and `aria-modal="true"` - Uses `aria-label` or `aria-labelledby` to identify the dialog - Uses `aria-describedby` to provide additional context +- Respects `prefers-reduced-motion: reduce` by disabling dialog overlay/backdrop and panel transitions diff --git a/apps/www/src/content/docs/components/drawer/index.mdx b/apps/www/src/content/docs/components/drawer/index.mdx index a54633317..c9d858642 100644 --- a/apps/www/src/content/docs/components/drawer/index.mdx +++ b/apps/www/src/content/docs/components/drawer/index.mdx @@ -80,4 +80,5 @@ The Drawer can slide in from different sides of the screen. Swipe-to-dismiss is - Focus is trapped within the drawer and restored on close - Supports dismissal with Escape key and swipe gestures - Title is announced via `aria-labelledby` +- Respects `prefers-reduced-motion: reduce` by disabling drawer slide/backdrop transitions diff --git a/apps/www/src/content/docs/components/link/index.mdx b/apps/www/src/content/docs/components/link/index.mdx index f994f6568..77d7ddaca 100644 --- a/apps/www/src/content/docs/components/link/index.mdx +++ b/apps/www/src/content/docs/components/link/index.mdx @@ -65,3 +65,4 @@ The Link component follows accessibility best practices: - External links have aria-labels indicating they open in new tabs - Download links include appropriate aria-labels - Maintains color contrast ratios for all variants +- Respects `prefers-reduced-motion: reduce` by disabling the hover opacity transition diff --git a/apps/www/src/content/docs/components/popover/index.mdx b/apps/www/src/content/docs/components/popover/index.mdx index dac86471c..c01a7a0f4 100644 --- a/apps/www/src/content/docs/components/popover/index.mdx +++ b/apps/www/src/content/docs/components/popover/index.mdx @@ -61,3 +61,4 @@ Customize how the popover aligns with its trigger. - Trigger uses `aria-haspopup` and `aria-expanded` attributes - Focus is managed when opening and closing the popover - Supports dismissal with Escape key +- Respects `prefers-reduced-motion: reduce` by disabling the popover entry animation diff --git a/apps/www/src/content/docs/components/skeleton/index.mdx b/apps/www/src/content/docs/components/skeleton/index.mdx index f8b824814..aeba7fa31 100644 --- a/apps/www/src/content/docs/components/skeleton/index.mdx +++ b/apps/www/src/content/docs/components/skeleton/index.mdx @@ -98,5 +98,5 @@ The Skeleton component follows accessibility best practices: - Uses semantic HTML elements - Provides appropriate ARIA attributes - Maintains sufficient color contrast -- Animation can be disabled for users who prefer reduced motion +- Respects `prefers-reduced-motion: reduce` by disabling the skeleton shimmer animation - Supports both block and inline layouts diff --git a/apps/www/src/content/docs/components/spinner/index.mdx b/apps/www/src/content/docs/components/spinner/index.mdx index c573fe3e1..ef3cb4af0 100644 --- a/apps/www/src/content/docs/components/spinner/index.mdx +++ b/apps/www/src/content/docs/components/spinner/index.mdx @@ -44,3 +44,4 @@ The Spinner component includes appropriate ARIA attributes for accessibility: - `role="status"`: Indicates that the element is a status indicator. - `aria-hidden="true"`: Hides the spinner from screen readers, as it's a visual indicator only. +- Respects `prefers-reduced-motion: reduce` by disabling spinner rotation animation diff --git a/apps/www/src/content/docs/components/toast/index.mdx b/apps/www/src/content/docs/components/toast/index.mdx index d53884bdf..c49ddd1b9 100644 --- a/apps/www/src/content/docs/components/toast/index.mdx +++ b/apps/www/src/content/docs/components/toast/index.mdx @@ -95,3 +95,4 @@ Create a toast, then update or close it programmatically using the returned ID. - Close button has `aria-label="Close toast"` - Supports keyboard navigation and Escape to dismiss - Swipe-to-dismiss gesture support +- Respects `prefers-reduced-motion: reduce` by disabling toast enter/exit transitions diff --git a/apps/www/src/content/docs/components/tooltip/index.mdx b/apps/www/src/content/docs/components/tooltip/index.mdx index 2c579400e..4ab069a11 100644 --- a/apps/www/src/content/docs/components/tooltip/index.mdx +++ b/apps/www/src/content/docs/components/tooltip/index.mdx @@ -83,3 +83,7 @@ Use `trackCursorAxis` prop on the Root component to make the tooltip follow the Show the arrow by setting `showArrow={true}` on the Content component: + +## Accessibility + +- Respects `prefers-reduced-motion: reduce` by disabling tooltip entry animations diff --git a/packages/raystack/components/accordion/accordion.module.css b/packages/raystack/components/accordion/accordion.module.css index a8db803e7..3132e61c2 100644 --- a/packages/raystack/components/accordion/accordion.module.css +++ b/packages/raystack/components/accordion/accordion.module.css @@ -77,3 +77,13 @@ padding: var(--rs-space-5) var(--rs-space-4); border-top: 0px; } + +@media (prefers-reduced-motion: reduce) { + .accordion-icon { + transition: none; + } + + .accordion-content { + transition: none; + } +} diff --git a/packages/raystack/components/button/button.module.css b/packages/raystack/components/button/button.module.css index 3fde77f6d..a9747b461 100644 --- a/packages/raystack/components/button/button.module.css +++ b/packages/raystack/components/button/button.module.css @@ -253,6 +253,13 @@ animation: spin 1s linear infinite; } +@media (prefers-reduced-motion: reduce) { + /* Disable button loader rotation for reduced-motion users. */ + .loader { + animation: none; + } +} + .loader-text { margin-left: var(--rs-space-3); } diff --git a/packages/raystack/components/collapsible/collapsible.module.css b/packages/raystack/components/collapsible/collapsible.module.css index d9791b672..6979a7404 100644 --- a/packages/raystack/components/collapsible/collapsible.module.css +++ b/packages/raystack/components/collapsible/collapsible.module.css @@ -18,3 +18,9 @@ .panel[data-ending-style] { height: 0; } + +@media (prefers-reduced-motion: reduce) { + .panel { + transition: none; + } +} diff --git a/packages/raystack/components/link/link.module.css b/packages/raystack/components/link/link.module.css index 844246429..8d6a2837a 100644 --- a/packages/raystack/components/link/link.module.css +++ b/packages/raystack/components/link/link.module.css @@ -7,3 +7,9 @@ .link:hover { opacity: 0.8; } + +@media (prefers-reduced-motion: reduce) { + .link { + transition: none; + } +} diff --git a/packages/raystack/components/popover/popover.module.css b/packages/raystack/components/popover/popover.module.css index 8da7a13ee..15d3389d0 100644 --- a/packages/raystack/components/popover/popover.module.css +++ b/packages/raystack/components/popover/popover.module.css @@ -29,3 +29,9 @@ transform: translateY(0); } } + +@media (prefers-reduced-motion: reduce) { + .popover { + animation: none; + } +} diff --git a/packages/raystack/components/skeleton/skeleton.module.css b/packages/raystack/components/skeleton/skeleton.module.css index 4abef1250..2654d35d2 100644 --- a/packages/raystack/components/skeleton/skeleton.module.css +++ b/packages/raystack/components/skeleton/skeleton.module.css @@ -36,3 +36,10 @@ } } +@media (prefers-reduced-motion: reduce) { + /* Disable shimmer animation for reduced-motion users. */ + .animate::after { + animation: none; + } +} + diff --git a/packages/raystack/components/spinner/spinner.module.css b/packages/raystack/components/spinner/spinner.module.css index b996568fa..a4e5f4f06 100644 --- a/packages/raystack/components/spinner/spinner.module.css +++ b/packages/raystack/components/spinner/spinner.module.css @@ -90,6 +90,13 @@ } } +@media (prefers-reduced-motion: reduce) { + /* Disable spinner rotation for reduced-motion users. */ + .pole { + animation: none; + } +} + .spinner-size-1 { width: var(--rs-space-4); height: var(--rs-space-4); diff --git a/packages/raystack/components/tooltip/tooltip.module.css b/packages/raystack/components/tooltip/tooltip.module.css index 7029ab080..166aa8c87 100644 --- a/packages/raystack/components/tooltip/tooltip.module.css +++ b/packages/raystack/components/tooltip/tooltip.module.css @@ -149,3 +149,9 @@ transform: translate(2px, 2px); } } + +@media (prefers-reduced-motion: reduce) { + .content { + animation: none !important; + } +} From 1f4053b9a9fc7fd523a66a90936388c89deb9d81 Mon Sep 17 00:00:00 2001 From: paanSinghCoder Date: Fri, 20 Mar 2026 16:56:59 +0530 Subject: [PATCH 2/4] style: prefer reduced motion --- .../src/content/docs/components/preview-card/index.mdx | 1 + .../components/preview-card/preview-card.module.css | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/apps/www/src/content/docs/components/preview-card/index.mdx b/apps/www/src/content/docs/components/preview-card/index.mdx index 4b6cc6e6c..9529d3f63 100644 --- a/apps/www/src/content/docs/components/preview-card/index.mdx +++ b/apps/www/src/content/docs/components/preview-card/index.mdx @@ -76,3 +76,4 @@ Control the position of the preview card relative to its trigger. - Closes when the pointer leaves the trigger or content area - Content is accessible to screen readers when open - Trigger renders as a semantic `` element +- Respects `prefers-reduced-motion: reduce` by disabling the preview card open/close transitions diff --git a/packages/raystack/components/preview-card/preview-card.module.css b/packages/raystack/components/preview-card/preview-card.module.css index 04a5ce504..ac8e5fa06 100644 --- a/packages/raystack/components/preview-card/preview-card.module.css +++ b/packages/raystack/components/preview-card/preview-card.module.css @@ -110,3 +110,13 @@ translate: -30% 0; opacity: 0; } + +@media (prefers-reduced-motion: reduce) { + /* Disable open/close transitions for reduced-motion users. */ + .positioner, + .popup, + .viewport [data-previous], + .viewport [data-current] { + transition: none; + } +} From 1ce25c956c3388c7ab5bf52a83ef622fbe04d081 Mon Sep 17 00:00:00 2001 From: paanSinghCoder Date: Tue, 7 Apr 2026 13:03:48 +0530 Subject: [PATCH 3/4] style: update motion preferences to enable transitions only when `prefers-reduced-motion: no-preference` --- .../docs/components/accordion/index.mdx | 2 +- .../docs/components/alert-dialog/index.mdx | 2 +- .../content/docs/components/button/index.mdx | 2 +- .../docs/components/collapsible/index.mdx | 2 +- .../content/docs/components/dialog/index.mdx | 2 +- .../content/docs/components/drawer/index.mdx | 2 +- .../content/docs/components/link/index.mdx | 2 +- .../content/docs/components/popover/index.mdx | 2 +- .../docs/components/preview-card/index.mdx | 2 +- .../content/docs/components/sidebar/index.mdx | 2 +- .../docs/components/skeleton/index.mdx | 2 +- .../content/docs/components/spinner/index.mdx | 2 +- .../content/docs/components/tabs/index.mdx | 2 +- .../content/docs/components/toast/index.mdx | 2 +- .../content/docs/components/tooltip/index.mdx | 2 +- .../components/accordion/accordion.module.css | 8 +-- .../components/button/button.module.css | 11 +-- .../raystack/components/chip/chip.module.css | 2 +- .../collapsible/collapsible.module.css | 5 +- .../components/dialog/dialog.module.css | 8 +-- .../components/drawer/drawer.module.css | 14 ++-- .../icon-button/icon-button.module.css | 2 +- .../input-field/input-field.module.css | 4 +- .../raystack/components/link/link.module.css | 6 -- .../components/meter/meter.module.css | 12 +++- .../components/navbar/navbar.module.css | 7 +- .../components/popover/popover.module.css | 5 +- .../preview-card/preview-card.module.css | 39 +++++++---- .../components/progress/progress.module.css | 12 +++- .../scroll-area/scroll-area.module.css | 14 ++-- .../components/select/select.module.css | 4 +- .../components/sidebar/sidebar.module.css | 12 ++-- .../components/skeleton/skeleton.module.css | 6 +- .../components/spinner/spinner.module.css | 6 +- .../components/switch/switch.module.css | 7 +- .../raystack/components/tabs/tabs.module.css | 16 ++--- .../components/text-area/text-area.module.css | 7 +- .../components/toast/toast.module.css | 18 ++--- .../components/tooltip/tooltip.module.css | 67 ++++++++++--------- 39 files changed, 170 insertions(+), 152 deletions(-) diff --git a/apps/www/src/content/docs/components/accordion/index.mdx b/apps/www/src/content/docs/components/accordion/index.mdx index a56fa334e..50c56b11d 100644 --- a/apps/www/src/content/docs/components/accordion/index.mdx +++ b/apps/www/src/content/docs/components/accordion/index.mdx @@ -90,4 +90,4 @@ The accordion content can contain any React elements, allowing for rich layouts - Trigger elements use `aria-expanded` to indicate open/closed state - Supports keyboard navigation with Enter and Space to toggle items - Content panels use `aria-controls` and `aria-labelledby` for association -- Respects `prefers-reduced-motion: reduce` by disabling the icon rotation transition and content height transition +- Respects motion preferences: icon rotation and panel expand/collapse motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/alert-dialog/index.mdx b/apps/www/src/content/docs/components/alert-dialog/index.mdx index f7ab58848..0230cdad6 100644 --- a/apps/www/src/content/docs/components/alert-dialog/index.mdx +++ b/apps/www/src/content/docs/components/alert-dialog/index.mdx @@ -121,4 +121,4 @@ You can nest alert dialogs for multi-step confirmation flows. When a nested aler - Uses `aria-label` or `aria-labelledby` to identify the dialog - Uses `aria-describedby` to provide additional context - Focus is trapped within the alert dialog while open -- Respects `prefers-reduced-motion: reduce` by disabling dialog overlay/panel transitions +- Respects motion preferences: alert dialog panel motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/button/index.mdx b/apps/www/src/content/docs/components/button/index.mdx index 8b3fab898..96b1afc30 100644 --- a/apps/www/src/content/docs/components/button/index.mdx +++ b/apps/www/src/content/docs/components/button/index.mdx @@ -75,4 +75,4 @@ The button component accepts optional leading and/or trailing icons. - Supports keyboard activation with Enter and Space keys - Disabled state is communicated via `aria-disabled` attribute - Loading state prevents interaction and announces status to screen readers -- Respects `prefers-reduced-motion: reduce` by disabling the button loader rotation animation +- Respects motion preferences: button loader rotation is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/collapsible/index.mdx b/apps/www/src/content/docs/components/collapsible/index.mdx index dd14c49a0..1c0a72506 100644 --- a/apps/www/src/content/docs/components/collapsible/index.mdx +++ b/apps/www/src/content/docs/components/collapsible/index.mdx @@ -72,4 +72,4 @@ The collapsible can be disabled to prevent user interaction. - The Trigger uses `aria-expanded` to indicate the open/closed state of the panel. - Supports keyboard interaction with Enter and Space to toggle the panel. - The Panel is automatically associated with the Trigger via `aria-controls`. -- Respects `prefers-reduced-motion: reduce` by disabling the panel height transition +- Respects motion preferences: panel expand/collapse motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/dialog/index.mdx b/apps/www/src/content/docs/components/dialog/index.mdx index 28bb0acfe..286b1fc36 100644 --- a/apps/www/src/content/docs/components/dialog/index.mdx +++ b/apps/www/src/content/docs/components/dialog/index.mdx @@ -123,4 +123,4 @@ You can nest dialogs within one another. When a nested dialog opens, the parent - Dialog has `role="dialog"` and `aria-modal="true"` - Uses `aria-label` or `aria-labelledby` to identify the dialog - Uses `aria-describedby` to provide additional context -- Respects `prefers-reduced-motion: reduce` by disabling dialog overlay/backdrop and panel transitions +- Respects motion preferences: dialog panel motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/drawer/index.mdx b/apps/www/src/content/docs/components/drawer/index.mdx index c9d858642..3ef11853e 100644 --- a/apps/www/src/content/docs/components/drawer/index.mdx +++ b/apps/www/src/content/docs/components/drawer/index.mdx @@ -80,5 +80,5 @@ The Drawer can slide in from different sides of the screen. Swipe-to-dismiss is - Focus is trapped within the drawer and restored on close - Supports dismissal with Escape key and swipe gestures - Title is announced via `aria-labelledby` -- Respects `prefers-reduced-motion: reduce` by disabling drawer slide/backdrop transitions +- Respects motion preferences: drawer slide motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/link/index.mdx b/apps/www/src/content/docs/components/link/index.mdx index 77d7ddaca..84f79b75a 100644 --- a/apps/www/src/content/docs/components/link/index.mdx +++ b/apps/www/src/content/docs/components/link/index.mdx @@ -65,4 +65,4 @@ The Link component follows accessibility best practices: - External links have aria-labels indicating they open in new tabs - Download links include appropriate aria-labels - Maintains color contrast ratios for all variants -- Respects `prefers-reduced-motion: reduce` by disabling the hover opacity transition +- Hover feedback uses an opacity transition diff --git a/apps/www/src/content/docs/components/popover/index.mdx b/apps/www/src/content/docs/components/popover/index.mdx index c01a7a0f4..bfba4b68d 100644 --- a/apps/www/src/content/docs/components/popover/index.mdx +++ b/apps/www/src/content/docs/components/popover/index.mdx @@ -61,4 +61,4 @@ Customize how the popover aligns with its trigger. - Trigger uses `aria-haspopup` and `aria-expanded` attributes - Focus is managed when opening and closing the popover - Supports dismissal with Escape key -- Respects `prefers-reduced-motion: reduce` by disabling the popover entry animation +- Respects motion preferences: popover entry motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/preview-card/index.mdx b/apps/www/src/content/docs/components/preview-card/index.mdx index 9529d3f63..36d4933f2 100644 --- a/apps/www/src/content/docs/components/preview-card/index.mdx +++ b/apps/www/src/content/docs/components/preview-card/index.mdx @@ -76,4 +76,4 @@ Control the position of the preview card relative to its trigger. - Closes when the pointer leaves the trigger or content area - Content is accessible to screen readers when open - Trigger renders as a semantic `` element -- Respects `prefers-reduced-motion: reduce` by disabling the preview card open/close transitions +- Respects motion preferences: preview card open/close motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/sidebar/index.mdx b/apps/www/src/content/docs/components/sidebar/index.mdx index 7b58eb0d5..636e4802d 100644 --- a/apps/www/src/content/docs/components/sidebar/index.mdx +++ b/apps/www/src/content/docs/components/sidebar/index.mdx @@ -103,7 +103,7 @@ Set `hideCollapsedItemTooltip` to disable tooltips on navigation items when the The Sidebar implements the following accessibility features: -- **Reduced motion** — Respects the user's motion preferences. When the system "Reduce motion" setting is enabled, collapse/expand and hover transitions are disabled so the sidebar updates without animation. +- **Reduced motion** — Sidebar collapse/expand motion is enabled only when `prefers-reduced-motion: no-preference`. - Proper ARIA roles and attributes diff --git a/apps/www/src/content/docs/components/skeleton/index.mdx b/apps/www/src/content/docs/components/skeleton/index.mdx index aeba7fa31..cad32ddc0 100644 --- a/apps/www/src/content/docs/components/skeleton/index.mdx +++ b/apps/www/src/content/docs/components/skeleton/index.mdx @@ -98,5 +98,5 @@ The Skeleton component follows accessibility best practices: - Uses semantic HTML elements - Provides appropriate ARIA attributes - Maintains sufficient color contrast -- Respects `prefers-reduced-motion: reduce` by disabling the skeleton shimmer animation +- Respects motion preferences: skeleton shimmer is enabled only when `prefers-reduced-motion: no-preference` - Supports both block and inline layouts diff --git a/apps/www/src/content/docs/components/spinner/index.mdx b/apps/www/src/content/docs/components/spinner/index.mdx index ef3cb4af0..e932f3add 100644 --- a/apps/www/src/content/docs/components/spinner/index.mdx +++ b/apps/www/src/content/docs/components/spinner/index.mdx @@ -44,4 +44,4 @@ The Spinner component includes appropriate ARIA attributes for accessibility: - `role="status"`: Indicates that the element is a status indicator. - `aria-hidden="true"`: Hides the spinner from screen readers, as it's a visual indicator only. -- Respects `prefers-reduced-motion: reduce` by disabling spinner rotation animation +- Respects motion preferences: spinner rotation is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/tabs/index.mdx b/apps/www/src/content/docs/components/tabs/index.mdx index 436956c0b..22acc3c73 100644 --- a/apps/www/src/content/docs/components/tabs/index.mdx +++ b/apps/www/src/content/docs/components/tabs/index.mdx @@ -70,4 +70,4 @@ Renders the content panel for a tab. - Uses `role="tablist"`, `role="tab"`, and `role="tabpanel"` - Active tab is indicated with `aria-selected` - Leading icon is wrapped with `aria-hidden` so it is not announced (treated as decorative) -- Respects `prefers-reduced-motion: reduce`: the tab indicator does not animate when the user has requested reduced motion in OS/browser settings +- Respects motion preferences: tab indicator motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/toast/index.mdx b/apps/www/src/content/docs/components/toast/index.mdx index c49ddd1b9..17962298f 100644 --- a/apps/www/src/content/docs/components/toast/index.mdx +++ b/apps/www/src/content/docs/components/toast/index.mdx @@ -95,4 +95,4 @@ Create a toast, then update or close it programmatically using the returned ID. - Close button has `aria-label="Close toast"` - Supports keyboard navigation and Escape to dismiss - Swipe-to-dismiss gesture support -- Respects `prefers-reduced-motion: reduce` by disabling toast enter/exit transitions +- Respects motion preferences: toast enter/exit motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/apps/www/src/content/docs/components/tooltip/index.mdx b/apps/www/src/content/docs/components/tooltip/index.mdx index 4ab069a11..7198906f5 100644 --- a/apps/www/src/content/docs/components/tooltip/index.mdx +++ b/apps/www/src/content/docs/components/tooltip/index.mdx @@ -86,4 +86,4 @@ Show the arrow by setting `showArrow={true}` on the Content component: ## Accessibility -- Respects `prefers-reduced-motion: reduce` by disabling tooltip entry animations +- Respects motion preferences: tooltip entry motion is enabled only when `prefers-reduced-motion: no-preference` diff --git a/packages/raystack/components/accordion/accordion.module.css b/packages/raystack/components/accordion/accordion.module.css index 3132e61c2..b6d460250 100644 --- a/packages/raystack/components/accordion/accordion.module.css +++ b/packages/raystack/components/accordion/accordion.module.css @@ -47,7 +47,6 @@ color: var(--rs-color-foreground-base-secondary); pointer-events: none; flex-shrink: 0; - transition: transform 150ms ease-in-out; width: var(--rs-space-4); height: var(--rs-space-4); } @@ -55,7 +54,6 @@ .accordion-content { height: var(--accordion-panel-height); overflow: hidden; - transition: height 150ms ease-out; } .accordion-content[data-starting-style], @@ -78,12 +76,12 @@ border-top: 0px; } -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .accordion-icon { - transition: none; + transition: transform 150ms ease-in-out; } .accordion-content { - transition: none; + transition: height 150ms ease-out; } } diff --git a/packages/raystack/components/button/button.module.css b/packages/raystack/components/button/button.module.css index a9747b461..ac93a0582 100644 --- a/packages/raystack/components/button/button.module.css +++ b/packages/raystack/components/button/button.module.css @@ -13,7 +13,6 @@ padding: var(--rs-space-3) var(--rs-space-4); border-radius: var(--rs-radius-2); text-wrap: nowrap; - transition: all 0.2s ease-in-out; } .button:focus-visible { @@ -250,13 +249,15 @@ border-radius: 50%; width: 10px; height: 10px; - animation: spin 1s linear infinite; } -@media (prefers-reduced-motion: reduce) { - /* Disable button loader rotation for reduced-motion users. */ +@media (prefers-reduced-motion: no-preference) { + .button { + transition: all 0.2s ease-in-out; + } + .loader { - animation: none; + animation: spin 1s linear infinite; } } diff --git a/packages/raystack/components/chip/chip.module.css b/packages/raystack/components/chip/chip.module.css index 76bed9e30..08f88cb3e 100644 --- a/packages/raystack/components/chip/chip.module.css +++ b/packages/raystack/components/chip/chip.module.css @@ -11,7 +11,7 @@ border-radius: var(--rs-radius-2); white-space: nowrap; cursor: default; - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; box-sizing: border-box; height: fit-content; width: fit-content; diff --git a/packages/raystack/components/collapsible/collapsible.module.css b/packages/raystack/components/collapsible/collapsible.module.css index 6979a7404..7c94e3b1d 100644 --- a/packages/raystack/components/collapsible/collapsible.module.css +++ b/packages/raystack/components/collapsible/collapsible.module.css @@ -11,7 +11,6 @@ .panel { height: var(--collapsible-panel-height); overflow: hidden; - transition: height 150ms ease-out; } .panel[data-starting-style], @@ -19,8 +18,8 @@ height: 0; } -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .panel { - transition: none; + transition: height 150ms ease-out; } } diff --git a/packages/raystack/components/dialog/dialog.module.css b/packages/raystack/components/dialog/dialog.module.css index 7cf020e82..2355b9894 100644 --- a/packages/raystack/components/dialog/dialog.module.css +++ b/packages/raystack/components/dialog/dialog.module.css @@ -23,7 +23,7 @@ position: fixed; top: 50%; left: 50%; - transition: all 150ms; + transition: opacity 150ms; transform: translate(-50%, -50%); } @@ -84,11 +84,9 @@ z-index: var(--rs-z-index-portal); } -@media (prefers-reduced-motion: reduce) { - .dialogOverlay, +@media (prefers-reduced-motion: no-preference) { .dialogContent { - animation: none; - transition: none; + transition: opacity 150ms, transform 150ms; } } diff --git a/packages/raystack/components/drawer/drawer.module.css b/packages/raystack/components/drawer/drawer.module.css index 419970cfa..e647143f9 100644 --- a/packages/raystack/components/drawer/drawer.module.css +++ b/packages/raystack/components/drawer/drawer.module.css @@ -73,7 +73,6 @@ .drawerPopup-right { width: 250px; height: 100%; - transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1); transform: translateX(var(--drawer-swipe-movement-x)); } @@ -90,7 +89,6 @@ .drawerPopup-left { width: 250px; height: 100%; - transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1); transform: translateX(var(--drawer-swipe-movement-x)); } @@ -107,7 +105,6 @@ .drawerPopup-top { width: 100%; height: 300px; - transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1); transform: translateY(var(--drawer-swipe-movement-y)); } @@ -124,7 +121,6 @@ .drawerPopup-bottom { width: 100%; height: 300px; - transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1); transform: translateY(var(--drawer-swipe-movement-y)); } @@ -201,9 +197,11 @@ border-top: 1px solid var(--rs-color-border-base-primary); } -@media (prefers-reduced-motion: reduce) { - .drawerPopup, - .backdrop { - transition: none; +@media (prefers-reduced-motion: no-preference) { + .drawerPopup-right, + .drawerPopup-left, + .drawerPopup-top, + .drawerPopup-bottom { + transition: transform 450ms cubic-bezier(0.32, 0.72, 0, 1); } } diff --git a/packages/raystack/components/icon-button/icon-button.module.css b/packages/raystack/components/icon-button/icon-button.module.css index 6c56aa2b7..1e5c914a6 100644 --- a/packages/raystack/components/icon-button/icon-button.module.css +++ b/packages/raystack/components/icon-button/icon-button.module.css @@ -8,7 +8,7 @@ border: none; color: var(--rs-color-foreground-base-primary); cursor: pointer; - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; padding: var(--rs-space-1); } diff --git a/packages/raystack/components/input-field/input-field.module.css b/packages/raystack/components/input-field/input-field.module.css index 429f22809..b7f72072c 100644 --- a/packages/raystack/components/input-field/input-field.module.css +++ b/packages/raystack/components/input-field/input-field.module.css @@ -29,7 +29,7 @@ border-radius: var(--rs-radius-2); border: 1px solid var(--rs-color-border-base-tertiary); background: var(--rs-color-background-base-primary); - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; box-sizing: border-box; overflow: hidden; } @@ -159,7 +159,7 @@ .has-chips { background: var(--rs-color-background-base-primary); - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; } .has-chips:hover { diff --git a/packages/raystack/components/link/link.module.css b/packages/raystack/components/link/link.module.css index 8d6a2837a..844246429 100644 --- a/packages/raystack/components/link/link.module.css +++ b/packages/raystack/components/link/link.module.css @@ -7,9 +7,3 @@ .link:hover { opacity: 0.8; } - -@media (prefers-reduced-motion: reduce) { - .link { - transition: none; - } -} diff --git a/packages/raystack/components/meter/meter.module.css b/packages/raystack/components/meter/meter.module.css index abd501237..4315aa10c 100644 --- a/packages/raystack/components/meter/meter.module.css +++ b/packages/raystack/components/meter/meter.module.css @@ -42,7 +42,6 @@ .indicator { height: 100%; background-color: var(--rs-color-background-accent-emphasis); - transition: width 500ms; } /* Circular variant — viewBox is 72×72, SVG scales to container size */ @@ -83,7 +82,16 @@ (1 - var(--rs-meter-percentage, 0) / 100) ); stroke-linecap: butt; - transition: stroke-dashoffset 500ms; +} + +@media (prefers-reduced-motion: no-preference) { + .indicator { + transition: width 500ms; + } + + .circularIndicatorCircle { + transition: stroke-dashoffset 500ms; + } } .meter-variant-circular .value { diff --git a/packages/raystack/components/navbar/navbar.module.css b/packages/raystack/components/navbar/navbar.module.css index 1dac86d82..90966faf6 100644 --- a/packages/raystack/components/navbar/navbar.module.css +++ b/packages/raystack/components/navbar/navbar.module.css @@ -7,7 +7,12 @@ box-shadow: var(--rs-shadow-feather); box-sizing: border-box; min-height: var(--rs-space-11); - transition: transform 0.2s ease-in-out; +} + +@media (prefers-reduced-motion: no-preference) { + .root { + transition: transform 0.2s ease-in-out; + } } .root[data-sticky="true"] { diff --git a/packages/raystack/components/popover/popover.module.css b/packages/raystack/components/popover/popover.module.css index 15d3389d0..7075b385f 100644 --- a/packages/raystack/components/popover/popover.module.css +++ b/packages/raystack/components/popover/popover.module.css @@ -16,7 +16,6 @@ box-shadow: var(--rs-shadow-soft); border: 1px solid var(--rs-color-border-base-primary); color: var(--rs-color-foreground-base-primary); - animation: slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1); } @keyframes slideUpAndFade { @@ -30,8 +29,8 @@ } } -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .popover { - animation: none; + animation: slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1); } } diff --git a/packages/raystack/components/preview-card/preview-card.module.css b/packages/raystack/components/preview-card/preview-card.module.css index ac8e5fa06..3fae83137 100644 --- a/packages/raystack/components/preview-card/preview-card.module.css +++ b/packages/raystack/components/preview-card/preview-card.module.css @@ -6,9 +6,7 @@ height: var(--positioner-height); width: var(--positioner-width); max-width: var(--available-width); - transition-property: top, left, right, bottom, transform; - transition-timing-function: var(--easing); - transition-duration: var(--animation-duration); + transition: opacity var(--animation-duration) var(--easing); } .popup { @@ -28,9 +26,7 @@ width: var(--popup-width, auto); height: var(--popup-height, auto); - transition-property: width, height, opacity, transform; - transition-timing-function: var(--easing); - transition-duration: var(--animation-duration); + transition: opacity var(--animation-duration) var(--easing); } .popup[data-starting-style], @@ -82,9 +78,7 @@ width: var(--popup-width); translate: 0; opacity: 1; - transition: - translate var(--animation-duration) var(--easing), - opacity calc(var(--animation-duration) / 2) var(--easing); + transition: opacity calc(var(--animation-duration) / 2) var(--easing); } .viewport[data-activation-direction~="left"] @@ -111,12 +105,29 @@ opacity: 0; } -@media (prefers-reduced-motion: reduce) { - /* Disable open/close transitions for reduced-motion users. */ - .positioner, - .popup, +@media (prefers-reduced-motion: no-preference) { + .positioner { + transition: + top var(--animation-duration) var(--easing), + left var(--animation-duration) var(--easing), + right var(--animation-duration) var(--easing), + bottom var(--animation-duration) var(--easing), + transform var(--animation-duration) var(--easing), + opacity var(--animation-duration) var(--easing); + } + + .popup { + transition: + width var(--animation-duration) var(--easing), + height var(--animation-duration) var(--easing), + opacity var(--animation-duration) var(--easing), + transform var(--animation-duration) var(--easing); + } + .viewport [data-previous], .viewport [data-current] { - transition: none; + transition: + translate var(--animation-duration) var(--easing), + opacity calc(var(--animation-duration) / 2) var(--easing); } } diff --git a/packages/raystack/components/progress/progress.module.css b/packages/raystack/components/progress/progress.module.css index 324d5a0ae..3b0f90010 100644 --- a/packages/raystack/components/progress/progress.module.css +++ b/packages/raystack/components/progress/progress.module.css @@ -42,7 +42,6 @@ .indicator { height: 100%; background-color: var(--rs-color-background-accent-emphasis); - transition: width 500ms; } /* Circular variant — viewBox is 72×72, SVG scales to container size */ @@ -83,7 +82,16 @@ (1 - var(--rs-progress-percentage, 0) / 100) ); stroke-linecap: butt; - transition: stroke-dashoffset 500ms; +} + +@media (prefers-reduced-motion: no-preference) { + .indicator { + transition: width 500ms; + } + + .circularIndicatorCircle { + transition: stroke-dashoffset 500ms; + } } .progress-variant-circular .value { diff --git a/packages/raystack/components/scroll-area/scroll-area.module.css b/packages/raystack/components/scroll-area/scroll-area.module.css index 39be70a82..1c753b1a6 100644 --- a/packages/raystack/components/scroll-area/scroll-area.module.css +++ b/packages/raystack/components/scroll-area/scroll-area.module.css @@ -25,10 +25,7 @@ background: transparent; pointer-events: auto; position: relative; - transition: - width 150ms ease-out, - height 150ms ease-out, - opacity 150ms ease-out; + transition: opacity 150ms ease-out; } .scrollbar[data-orientation="vertical"] { @@ -58,6 +55,15 @@ touch-action: none; } +@media (prefers-reduced-motion: no-preference) { + .scrollbar { + transition: + width 150ms ease-out, + height 150ms ease-out, + opacity 150ms ease-out; + } +} + .corner { background: transparent; } diff --git a/packages/raystack/components/select/select.module.css b/packages/raystack/components/select/select.module.css index 7c4e3c729..0d961978e 100644 --- a/packages/raystack/components/select/select.module.css +++ b/packages/raystack/components/select/select.module.css @@ -13,7 +13,7 @@ box-shadow: var(--rs-shadow-soft); border: 0.5px solid var(--rs-color-border-base-primary); min-width: var(--anchor-width); - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; max-height: 320px; position: relative; overflow: auto; @@ -70,7 +70,7 @@ letter-spacing: var(--rs-letter-spacing-small); user-select: none; -webkit-user-select: none; - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; box-shadow: var(--rs-shadow-feather); } diff --git a/packages/raystack/components/sidebar/sidebar.module.css b/packages/raystack/components/sidebar/sidebar.module.css index 42e4ac51b..64558cf9b 100644 --- a/packages/raystack/components/sidebar/sidebar.module.css +++ b/packages/raystack/components/sidebar/sidebar.module.css @@ -8,7 +8,6 @@ align-items: flex-start; flex-shrink: 0; background: var(--rs-color-background-base-primary); - transition: width 0.2s ease; position: relative; } @@ -69,7 +68,7 @@ color: var(--rs-color-foreground-base-secondary); cursor: pointer; text-decoration: none; - transition: all 0.2s ease; + transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; box-sizing: border-box; } @@ -204,11 +203,8 @@ /* Keep in flow (no display: none) so header row height is preserved */ } -@media (prefers-reduced-motion: reduce) { - .root, - .nav-item, - .nav-text, - .resizeHandle { - transition: none; +@media (prefers-reduced-motion: no-preference) { + .root { + transition: width 0.2s ease; } } diff --git a/packages/raystack/components/skeleton/skeleton.module.css b/packages/raystack/components/skeleton/skeleton.module.css index 2654d35d2..f495b4e32 100644 --- a/packages/raystack/components/skeleton/skeleton.module.css +++ b/packages/raystack/components/skeleton/skeleton.module.css @@ -24,7 +24,6 @@ var(--skeleton-highlight-color), transparent ); - animation: shimmer var(--skeleton-duration) infinite; } @keyframes shimmer { @@ -36,10 +35,9 @@ } } -@media (prefers-reduced-motion: reduce) { - /* Disable shimmer animation for reduced-motion users. */ +@media (prefers-reduced-motion: no-preference) { .animate::after { - animation: none; + animation: shimmer var(--skeleton-duration) infinite; } } diff --git a/packages/raystack/components/spinner/spinner.module.css b/packages/raystack/components/spinner/spinner.module.css index a4e5f4f06..c3e9f7d16 100644 --- a/packages/raystack/components/spinner/spinner.module.css +++ b/packages/raystack/components/spinner/spinner.module.css @@ -11,7 +11,6 @@ height: 30%; background-color: currentColor; border-radius: var(--rs-radius-full); - animation: spin 1.2s linear infinite; transform-origin: center 150%; } @@ -90,10 +89,9 @@ } } -@media (prefers-reduced-motion: reduce) { - /* Disable spinner rotation for reduced-motion users. */ +@media (prefers-reduced-motion: no-preference) { .pole { - animation: none; + animation: spin 1.2s linear infinite; } } diff --git a/packages/raystack/components/switch/switch.module.css b/packages/raystack/components/switch/switch.module.css index 9b1827901..a78f8cd63 100644 --- a/packages/raystack/components/switch/switch.module.css +++ b/packages/raystack/components/switch/switch.module.css @@ -50,10 +50,15 @@ background: var(--rs-color-foreground-base-emphasis); border-radius: var(--rs-radius-full); transform: translateX(2px); - transition: transform 200ms ease-in-out; will-change: transform; } +@media (prefers-reduced-motion: no-preference) { + .thumb { + transition: transform 200ms ease-in-out; + } +} + /* Small switch thumb sizing */ .switch.small .thumb { width: 12px; diff --git a/packages/raystack/components/tabs/tabs.module.css b/packages/raystack/components/tabs/tabs.module.css index 9261fc44e..adef5c4de 100644 --- a/packages/raystack/components/tabs/tabs.module.css +++ b/packages/raystack/components/tabs/tabs.module.css @@ -74,11 +74,6 @@ background-color: var(--rs-color-background-base-primary); border-radius: var(--rs-radius-2); box-shadow: var(--rs-shadow-feather); - transition: - top 0.25s cubic-bezier(0.4, 0, 0.2, 1), - left 0.25s cubic-bezier(0.4, 0, 0.2, 1), - width 0.25s cubic-bezier(0.4, 0, 0.2, 1), - height 0.25s cubic-bezier(0.4, 0, 0.2, 1); top: var(--active-tab-top, 0); left: var(--active-tab-left, 0); width: var(--active-tab-width, 0); @@ -86,12 +81,13 @@ z-index: 0; } -/* Media query that matches when the user has -asked the OS/browser for less or no motion -(e.g. “Reduce motion” in accessibility settings). */ -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .indicator { - transition: none; + transition: + top 0.25s cubic-bezier(0.4, 0, 0.2, 1), + left 0.25s cubic-bezier(0.4, 0, 0.2, 1), + width 0.25s cubic-bezier(0.4, 0, 0.2, 1), + height 0.25s cubic-bezier(0.4, 0, 0.2, 1); } } diff --git a/packages/raystack/components/text-area/text-area.module.css b/packages/raystack/components/text-area/text-area.module.css index 2c822f275..a9ac43dfc 100644 --- a/packages/raystack/components/text-area/text-area.module.css +++ b/packages/raystack/components/text-area/text-area.module.css @@ -62,10 +62,15 @@ line-height: var(--rs-line-height-small); color: var(--rs-color-foreground-base-primary); padding: var(--rs-space-3); - transition: all 0.2s ease; overflow: hidden; } +@media (prefers-reduced-motion: no-preference) { + .textarea { + transition: all 0.2s ease; + } +} + .textarea:hover { border-color: var(--rs-color-border-base-focus); background: var(--rs-color-background-base-primary-hover); diff --git a/packages/raystack/components/toast/toast.module.css b/packages/raystack/components/toast/toast.module.css index 81d9e4f7e..e27f9b8a8 100644 --- a/packages/raystack/components/toast/toast.module.css +++ b/packages/raystack/components/toast/toast.module.css @@ -66,10 +66,7 @@ cursor: default; z-index: calc(1000 - var(--toast-index)); - transition: - transform 500ms cubic-bezier(0.22, 1, 0.36, 1), - opacity 500ms, - height 150ms; + transition: opacity 500ms; } /* ===== Vertical position: bottom ===== */ @@ -283,14 +280,11 @@ opacity: 0.85; } -/* ===== Reduced motion ===== */ -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .root { - transition: none; - } - - .root[data-starting-style], - .root[data-ending-style] { - transform: none; + transition: + transform 500ms cubic-bezier(0.22, 1, 0.36, 1), + opacity 500ms, + height 150ms; } } diff --git a/packages/raystack/components/tooltip/tooltip.module.css b/packages/raystack/components/tooltip/tooltip.module.css index 166aa8c87..663ddfccd 100644 --- a/packages/raystack/components/tooltip/tooltip.module.css +++ b/packages/raystack/components/tooltip/tooltip.module.css @@ -21,40 +21,9 @@ letter-spacing: var(--rs-letter-spacing-mini); width: fit-content; max-width: 400px; - animation-duration: 400ms; transform-origin: var(--transform-origin); } -.content[data-open][data-side="top"]:not([data-instant]) { - animation-name: slideDownAndFade; -} - -.content[data-open][data-side="right"]:not([data-instant]) { - animation-name: slideLeftAndFade; -} - -.content[data-open][data-side="bottom"]:not([data-instant]) { - animation-name: slideUpAndFade; -} - -.content[data-open][data-side="left"]:not([data-instant]) { - animation-name: slideRightAndFade; -} -.content[data-side="top"][data-align="start"]:not([data-instant]) { - animation-name: slideDownRightAndFade; -} - -.content[data-side="top"][data-align="end"]:not([data-instant]) { - animation-name: slideDownLeftAndFade; -} - -.content[data-side="bottom"][data-align="start"]:not([data-instant]) { - animation-name: slideUpRightAndFade; -} - -.content[data-side="bottom"][data-align="end"]:not([data-instant]) { - animation-name: slideUpLeftAndFade; -} .arrow svg { color: var(--rs-color-background-base-primary); @@ -150,8 +119,40 @@ } } -@media (prefers-reduced-motion: reduce) { +@media (prefers-reduced-motion: no-preference) { .content { - animation: none !important; + animation-duration: 400ms; + } + + .content[data-open][data-side="top"]:not([data-instant]) { + animation-name: slideDownAndFade; + } + + .content[data-open][data-side="right"]:not([data-instant]) { + animation-name: slideLeftAndFade; + } + + .content[data-open][data-side="bottom"]:not([data-instant]) { + animation-name: slideUpAndFade; + } + + .content[data-open][data-side="left"]:not([data-instant]) { + animation-name: slideRightAndFade; + } + + .content[data-side="top"][data-align="start"]:not([data-instant]) { + animation-name: slideDownRightAndFade; + } + + .content[data-side="top"][data-align="end"]:not([data-instant]) { + animation-name: slideDownLeftAndFade; + } + + .content[data-side="bottom"][data-align="start"]:not([data-instant]) { + animation-name: slideUpRightAndFade; + } + + .content[data-side="bottom"][data-align="end"]:not([data-instant]) { + animation-name: slideUpLeftAndFade; } } From e32e178dc00a555b2e8f86397404577b536a25e6 Mon Sep 17 00:00:00 2001 From: paanSinghCoder Date: Tue, 7 Apr 2026 14:36:08 +0530 Subject: [PATCH 4/4] style: unify transition properties across components using CSS variables --- packages/raystack/components/chip/chip.module.css | 2 +- .../raystack/components/icon-button/icon-button.module.css | 2 +- .../raystack/components/input-field/input-field.module.css | 4 ++-- packages/raystack/components/select/select.module.css | 2 +- packages/raystack/styles/effects.css | 3 +++ 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/raystack/components/chip/chip.module.css b/packages/raystack/components/chip/chip.module.css index d1f06670c..ff131ee85 100644 --- a/packages/raystack/components/chip/chip.module.css +++ b/packages/raystack/components/chip/chip.module.css @@ -11,7 +11,7 @@ border-radius: var(--rs-radius-2); white-space: nowrap; cursor: default; - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + transition: var(--rs-transition-interactive); box-sizing: border-box; height: fit-content; width: fit-content; diff --git a/packages/raystack/components/icon-button/icon-button.module.css b/packages/raystack/components/icon-button/icon-button.module.css index 317991e82..0fe473757 100644 --- a/packages/raystack/components/icon-button/icon-button.module.css +++ b/packages/raystack/components/icon-button/icon-button.module.css @@ -8,7 +8,7 @@ border: none; color: var(--rs-color-foreground-base-primary); cursor: pointer; - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + transition: var(--rs-transition-interactive); padding: var(--rs-space-1); } diff --git a/packages/raystack/components/input-field/input-field.module.css b/packages/raystack/components/input-field/input-field.module.css index 0da4e3292..253520a48 100644 --- a/packages/raystack/components/input-field/input-field.module.css +++ b/packages/raystack/components/input-field/input-field.module.css @@ -29,7 +29,7 @@ border-radius: var(--rs-radius-2); border: 0.5px solid var(--rs-color-border-base-tertiary); background: var(--rs-color-background-base-primary); - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + transition: var(--rs-transition-interactive); box-sizing: border-box; overflow: hidden; } @@ -155,7 +155,7 @@ .has-chips { background: var(--rs-color-background-base-primary); - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + transition: var(--rs-transition-interactive); } .has-chips:hover { diff --git a/packages/raystack/components/select/select.module.css b/packages/raystack/components/select/select.module.css index 9b2de2b6c..b1ff2862a 100644 --- a/packages/raystack/components/select/select.module.css +++ b/packages/raystack/components/select/select.module.css @@ -13,7 +13,7 @@ box-shadow: var(--rs-shadow-soft); border: 0.5px solid var(--rs-color-border-base-primary); min-width: var(--anchor-width); - transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + transition: var(--rs-transition-interactive); max-height: 320px; position: relative; overflow: auto; diff --git a/packages/raystack/styles/effects.css b/packages/raystack/styles/effects.css index 74a6980bc..e660054b4 100644 --- a/packages/raystack/styles/effects.css +++ b/packages/raystack/styles/effects.css @@ -7,6 +7,9 @@ --rs-shadow-floating: 0px 1px 1px 0px rgba(0, 0, 0, 0.04), 0px 2px 8px 0px rgba(0, 0, 0, 0.04), 0px 3px 17px 0px rgba(0, 0, 0, 0.04), 0px 4px 30px 0px rgba(0, 0, 0, 0.13); /* xl */ --rs-shadow-inset: 0px 1px 1px 0px rgba(0, 0, 0, 0.04) inset; + /* Transitions */ + --rs-transition-interactive: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + /* Blurs */ /* Example usage: backdrop-filter:: var(--rs-blur-sm); */ --rs-blur-sm: blur(0.5px);