Animation in module is not defined
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 21.8k
- Forks
- 1.1k
- Avg merge
- 18h 25m
- Merged PRs (30d)
- 2
Description
### Which package(s) are affected?
Lit Core (lit / lit-html / lit-element / reactive-element)
### Description
In some instances, animation will be undefined when used in a css module. I say some instances, because it is not 100% consistent and only happens on some of my custom elements and the logic is the same as the custom elements it does work in.(meaning there is nothing specific to do to reproduce it)
Note: in this instance, the `fadeoutother` animation is the one not defined
**Here it is working successfully when animation is not in css module**
```js
% cat elements/sort-dialog.js
import {
LitElement,
html,
css,
} from 'lit';
import '@material/mwc-tab-bar';
import '@material/mwc-tab';
import {
hideHostFade,
fadeinother,
} from '../common-styles.js';
import '@material/mwc-radio';
import { AnimationMixin } from '../mixins/animations-mixin.js';
export class SortDialog extends AnimationMixin(LitElement) {
static styles = [
hideHostFade,
fadeinother,
css`
:host([active]) {
display: flex;
}
:host([fadeoutother]) {
animation: fadeoutother 150ms ease-in-out forwards;
}
@keyframes fadeoutother {
0% {
visibility: visible;
opacity: 1;
}
100% {
visibility: hidden;
opacity: 0;
}
}
.body {
background-color: white;
width: 50%;
height: 50%;
margin: auto;
padding: 24px;
}
`,
];
static properties = {
};
constructor() {
super();
this.addEventListener('click', (e) => {
const { localName } = e.composedPath()[0];
if (localName === 'sort-dialog') {
this.setAttribute('fadeoutother', "");
}
});
}
render() {
return html`
Sorty by
`
}
_dispatchEvent() {
const opts = { bubbles: true };
this.dispatchEvent(new CustomEvent('sort-by-changed'));
}
changeRadio(e) {
const { value } = e.target.dataset;
localStorage.setItem("sortBy", value);
this.setAttribute('fadeoutother', "");
this._dispatchEvent();
}
getRadioValue(type) {
const storeValue = localStorage.getItem('sortBy') || 'date';
if (storeValue === type) {
return true;
}
return false;
}
connectedCallback() {
super.connectedCallback();
this._setEventToLeave('fadeoutother');
}
}
window.customElements.define('sort-dialog', SortDialog);
```

--------------------------------------------------------------------------------
**Here it is not working:**
```js
% cat elements/sort-dialog.js
import {
LitElement,
html,
css,
} from 'lit';
import '@material/mwc-tab-bar';
import '@material/mwc-tab';
import {
hideHostFade,
fadeoutother,
fadeinother,
} from '../common-styles.js';
import '@material/mwc-radio';
import { AnimationMixin } from '../mixins/animations-mixin.js';
export class SortDialog extends AnimationMixin(LitElement) {
static styles = [
hideHostFade,
fadeoutother,
fadeinother,
css`
:host([active]) {
display: flex;
}
.body {
background-color: white;
width: 50%;
height: 50%;
margin: auto;
padding: 24px;
}
`,
];
static properties = {
};
constructor() {
super();
this.addEventListener('click', (e) => {
const { localName } = e.composedPath()[0];
if (localName === 'sort-dialog') {
this.setAttribute('fadeoutother', "");
}
});
}
render() {
return html`
Sorty by
`
}
_dispatchEvent() {
const opts = { bubbles: true };
this.dispatchEvent(new CustomEvent('sort-by-changed'));
}
changeRadio(e) {
const { value } = e.target.dataset;
localStorage.setItem("sortBy", value);
this.setAttribute('fadeoutother', "");
this._dispatchEvent();
}
getRadioValue(type) {
const storeValue = localStorage.getItem('sortBy') || 'date';
if (storeValue === type) {
return true;
}
return false;
}
connectedCallback() {
super.connectedCallback();
this._setEventToLeave('fadeoutother');
}
}
window.customElements.define('sort-dialog', SortDialog);
```
```css
% cat common-styles.js
import { css } from 'lit';
const misc = css`
.blue-button {
color: white;
background-color: blue;
}
.blue-button:disabled {
background-color: grey;
}
ul {
list-style-type: none;
padding: 0;
}
svg {
fill: #686869;
}
.star-filled-icon {
fill: #00668c;
}
.btn-1 {
border-radius: 28px;
height: 40px;
border: none;
font-family: 'Roboto';
padding: 0 24px 0;
}
`;
const overlay = css`
.overlay {
position: relative;
height: 100vh;
width: 100%;
top: 0;
bottom: 0;
}
`;
const hideHostFade = css`
:host {
background: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
visibility: hidden;
opactiy: 0;
}
`;
const hideHost = css`
:host {
background: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
margin-top: 100vh;
}
`;
const fadeout = css`
:host([fadeout]) {
animation: fadeout 150ms ease-in-out forwards;
}
@keyframes fadeout {
0% {
visibility: visible;
opacity: 1;
}
100% {
visibility: hidden;
opacity: 0;
}
}
`;
const fadeoutother = css`
:host([fadeoutother]) {
animation: fadeoutother 150ms ease-in-out forwards;
}
@keyframes fadeoutother {
0% {
visibility: visible;
opacity: 1;
}
100% {
visibility: hidden;
opacity: 0;
}
}
`;
const fadeinother = css`
:host([fadeinother]) {
animation: fadeinother 150ms ease-in-out forwards 50ms;
}
@keyframes fadeinother {
0% {
visibility: visible;
opacity: 0;
}
100% {
visibility: visible;
opacity: 1;
}
}
`;
const pageTransitionStyles = css`
:host([active]) {
display: block;
}
:host([riseup]) {
display: block;
animation: riseup 125ms ease-in-out forwards 50ms;
}
:host([fadein]) {
animation: fadein 150ms ease-in-out forwards 50ms;
}
:host([slidedown]) {
margin-top: 0;
animation: slidedown 150ms ease-in-out forwards 50ms;
}
@keyframes riseup {
0% {
margin-top: 100vh;
}
100% {
margin-top: 0;
}
}
@keyframes slidedown {
0% {
margin-top: 0;
}
100% {
margin-top: 100vh;
}
}
`;
export {
pageTransitionStyles,
misc,
overlay,
hideHost,
hideHostFade,
fadeout,
fadeoutother,
fadeinother,
};
```

### Reproduction
na
### Workaround
do not use animation in module, use it in component instead
### Is this a regression?
No or unsure. This never worked, or I haven't tried before.
### Affected versions
2.7.4
### Browser/OS/Node environment
```
% node --version
v18.10.0
% npm list | grep -i lit
├── lit-analyzer@1.2.1
├── lit@2.7.4
% google-chrome-stable --version
Google Chrome 115.0.5790.110
% uname -a
Linux localhost 5.4.0-153-generic #170-Ubuntu SMP Fri Jun 16 13:43:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the two examples in elements/sort-dialog.js and common-styles.js, then inspect the relevant CSS module handling for keyframes. Reproduce the difference between inline and imported fadeoutother styles, and add a regression test that captures the failing case. Done means the imported animation is defined and the test passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css, javascript
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100