Add motion design tokens (duration and easing) to @wordpress/theme#76097
Add motion design tokens (duration and easing) to @wordpress/theme#76097jameskoster wants to merge 5 commits intotrunkfrom
Conversation
|
Size Change: +127 B (0%) Total Size: 8.76 MB
ℹ️ View Unchanged
|
mirka
left a comment
There was a problem hiding this comment.
Here's some context on why I'm hesitant to add motion tokens in this manner.
- If motion is not going to be themed dynamically through
ThemeProvider, it isn't necessary to manage as a official design token. (Which is good for avoiding token bloat in the stylesheet. But @aduth has suggested that we can manage tokens in the theme package as a central "data store", while still omitting them from the tokens stylesheet, so that could be a mitigation option.) - Most motion is already encapsulated at relatively higher levels (e.g. Tooltip/Dialog components, dropdown motion module, focus module). Which is both sufficient and easier for motion sharing across similar components.
- At the moment, there are Framer Motion usages that can't use values from CSS variables (not a blocker per se, but needs some planning on what to do).
So motion is one of those categories where I think we need to weight the cost–benefit. Maybe my intuition of the cost is overblown, and benefit underestimated.
These are just my hesitations — open to everyone's thoughts!
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
I defer to y'all on the implementation :) What's not clear to me is how we'd ensure consistent profiles (easing, duration) across components without tokens. Is that something we'd have to maintain manually?
Could there be a world where it is theme-able? For instance would it make sense for |
I think this strikes at an interesting question about what values make sense to be a design token. This interpretation reads to me as being based on the ability to customize, though I've personally approached it more as encoding design decisions that apply uniformly across components, that we can update in one place and cascade (single source of truth), and that can be used in the design process (e.g. Figma variables) for better code/design parity. In particular, the way these are being proposed feel to me like they aren't tied to any one specific component but apply generally across the system. I'm not as sure about design tooling, but it feels like a value we'd want to expose and use in motion design. Or maybe reframing: What is it about what's said about how we can manage motion through higher-level abstractions that is untrue about how we think about typography or color, for example? |
I guess a large part of my skepticism is about the validity of encoding the motion design decisions at the individual CSS property level.
|
|
Another fun thought that came to mind in support of higher-level encapsulation! Let's say we had an "intensity" setting for motion, where high intensity is very fun and low intensity is more calm. Could this be achieved globally by changing token values at a CSS property level? I'd say no. Each motion module (tooltips, dialogs, etc) needs to tweak itself appropriately for each intensity level, which would probably be switched by entire declaration blocks via a data attribute. |
Doesn't it make sense to handle this via ThemeProvider though, like all other theming aspects? With higher-level encapsulation could motion still be themeable if we introduced and utilised a wider range of motion primitives in the theme package, maybe with modes for different styles? |
|
I see both sides of the argument. Personally, I like the idea that shared variables all come as DS tokens. If we keep the stylesheet around, we don't really have to include these tokens in |
It will be handled by rather than: So while tokens could be beneficial if it's important to "quantize" durations and easings across the ecosystem to a certain set of values, it's not a requirement for overall motion consistency or motion theming. Consistency and theming will need to be addressed at higher levels anyway. |
|
Would it not be useful to have a set of tokens to utilise like so? This would give third parties building custom components a set of tokens to maintain coherent animation profiles with the system (and inherit any updates we make automatically). Or is the point that tokens like Sorry if I'm missing something obvious. |
Yes, if the point is to quantize values across the system, I'm not against that or anything. Let's try it out. |
|
I think the duration tokens are probably okay for a start, but how do you feel about the easing tokens? I'm wondering if there should be more of a scale, e.g. |
I have no idea actually. I think it's something that needs to be factored out of the actual animations that are going to be used? In other words, if we aren't sure yet, it could be fine to leave it out for now and add the tokens when we have a better idea of what is needed. |
|
Heh, I (softly) take the opposite position where the system provides some guardrails that inform what's possible rather than trying to extract tokens from patterns. I worry the latter could result in a lack of cohesion. Because the tokens would be semantic, introducing something lightweight now shouldn’t lock us in. We could start consuming them in a few prominent examples (Modal/Dialog, Menu, etc.) – maybe even in this PR to test – then iterate (and expand the tokens) later as needed. |
|
Sure, I'm fine with that too 👍 |
|
I updated |
Introduces standardized duration and easing tokens for consistent animation timing across components. Includes a Storybook story with interactive demos and usage guidance for each token. Made-with: Cursor
Replace hardcoded duration and easing values with --wpds-motion-* design tokens in UI/Dialog, Components/Modal, and UI dropdown motion. Components/Menu retains computed strings due to Emotion compatibility constraints (no-ds-tokens ESLint rule). Made-with: Cursor
d234848 to
93122b3
Compare
|
Flaky tests detected in 1c837c0. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/23243180871
|
There was a problem hiding this comment.
Probably makes sense to move this file to the root storybook folder so we can just use @wordpress/ui components and avoid a lot of custom CSS?
There was a problem hiding this comment.
Do you mean just this file or the whole story?
There was a problem hiding this comment.
I think I worked out what you meant, and updated accordingly. We'll need to consolidate our separate token folders at some point, but that doesn't need to happen here(?).
If I got it wrong let me know 😅
There was a problem hiding this comment.
Yeah my wording was off. What you did is correct, thanks 😄
| const EASING_TOKENS = [ | ||
| { | ||
| name: 'standard', | ||
| variable: 'var(--wpds-motion-easing-standard)', | ||
| description: 'State changes like hover, color, and toggle transitions.', | ||
| }, | ||
| { | ||
| name: 'decelerate', | ||
| variable: 'var(--wpds-motion-easing-decelerate)', | ||
| description: | ||
| 'Elements entering the screen, such as menus and popovers.', | ||
| }, |
There was a problem hiding this comment.
It isn't great that we need to define these manually when the data is all already available in the token store, but just not fully exposed in @wordpress/theme/design-tokens.js. Not a blocker, but I will see what we can do to make this easier.
There was a problem hiding this comment.
Coincidentally, this ☝️ can also help us with the token usage in all the JS files! We can expose the actual token data, not just the metadata. Win.
Co-authored-by: Lena Morita <lena@jaguchi.com>
Move the motion tokens story out of `packages/theme/src/stories/` and into `storybook/stories/design-system/tokens/` so it can use existing components (`Stack` from `@wordpress/ui`, `Button`/`SelectControl`/ `TextControl` from `@wordpress/components`) instead of hand-rolled CSS. This reduces the CSS module from 124 lines to 42, keeping only the animation-specific styles (track, dot, keyframes, typography). Made-with: Cursor
| function: 'cubic-bezier', | ||
| args: [ 0, 0, 0, 1 ] as const, | ||
| }, | ||
| FADE_DURATION: 80, |
There was a problem hiding this comment.
Right?
| FADE_DURATION: 100, |
There was a problem hiding this comment.
Yeah my wording was off. What you did is correct, thanks 😄
| const EASING_TOKENS = [ | ||
| { | ||
| name: 'standard', | ||
| variable: 'var(--wpds-motion-easing-standard)', | ||
| description: 'State changes like hover, color, and toggle transitions.', | ||
| }, | ||
| { | ||
| name: 'decelerate', | ||
| variable: 'var(--wpds-motion-easing-decelerate)', | ||
| description: | ||
| 'Elements entering the screen, such as menus and popovers.', | ||
| }, |
There was a problem hiding this comment.
Coincidentally, this ☝️ can also help us with the token usage in all the JS files! We can expose the actual token data, not just the metadata. Win.
Screen.Recording.2026-03-03.at.16.33.21.mov
What
Adds motion design tokens to
@wordpress/theme— a set of duration and easing curve tokens for standardizing animation timing across components — and adopts them in Dialog, Modal, and Menu/DropdownMenu.Duration tokens
--wpds-motion-duration-xs50ms--wpds-motion-duration-sm100ms--wpds-motion-duration-md200ms--wpds-motion-duration-lg300ms--wpds-motion-duration-xl400msEasing tokens
--wpds-motion-easing-standardcubic-bezier(0.4, 0, 0.2, 1)--wpds-motion-easing-deceleratecubic-bezier(0, 0, 0, 1)--wpds-motion-easing-acceleratecubic-bezier(1, 0, 1, 1)--wpds-motion-easing-emphasized-deceleratecubic-bezier(0.29, 0, 0, 1)--wpds-motion-easing-emphasized-acceleratecubic-bezier(1, 0, 0.2, 1)Why
Animation timing is currently hardcoded across components with magic numbers. The
Dialogcomponent, for example, uses0.2s cubic-bezier(0.29, 0, 0, 1)for its entrance and0.2s cubic-bezier(1, 0, 0.2, 1)for its exit — values that were chosen thoughtfully but aren't reusable by other components.Centralizing these values as tokens:
Design decisions
Easing curve values: The
emphasized-decelerateandemphasized-acceleratecurves are taken directly from the existingDialogcomponent to maintain backward compatibility. When Dialog adopts these tokens, its animations are unchanged.Easing vs. enter/exit naming: The tokens use descriptive physics-based names (
decelerate,accelerate) rather than semantic names (enter,exit). This is more flexible; a deceleration curve is primarily used for entrances, but could also suit other scenarios where an element needs to settle into place.Duration scale: The five-step
xs–xlscale provides enough granularity without being overwhelming. The descriptions intentionally avoid prescribing specific components to specific durations, since the right choice depends on the element's size, prominence, and context.How
Token definition
packages/theme/tokens/motion.json(DTCG format, withdurationandcubicBeziertypes)terrazzo.config.tsto include the new file and generateDurationSizeandEasingTypeScript typesmotion.story.tsx) with interactive animation demosToken adoption
UI/Dialog (
packages/ui/src/dialog/style.module.css): Replaced all three hardcoded duration+easing pairs (backdrop, popup enter, popup exit) with motion token variables. No visual change.Components/Modal (
packages/components/src/modal/):cubic-bezier()easing values with--wpds-motion-easing-emphasized-decelerateand--wpds-motion-easing-emphasized-acceleratetokens. No visual change.--modal-frame-animation-durationcustom property with--wpds-motion-duration-mdapplied directly in CSS, removingframeStylefrom the exit animation hook and the component.@wordpress/base-stylesfade mixins with local keyframes using--wpds-motion-duration-smfor the backdrop fade.Components/Menu and DropdownMenu (
packages/components/src/utils/dropdown-motion.ts,packages/ui/src/utils/css/dropdown-motion.module.css):dropdown-motion.module.css) now uses--wpds-motion-duration-md,--wpds-motion-easing-decelerate, and--wpds-motion-duration-smtokens directly.dropdown-motion.ts) retain hardcoded values because theno-ds-tokensESLint rule prevents--wpds-*usage inpackages/components/src/(incompatible with Emotion's build-time fallback injection). A comment documents the constraint and notes that values should stay in sync with the tokens.Testing
npm run --workspace @wordpress/theme buildto verify the token build succeedsdesign-tokens.css