Skip to content

design-system-react-components Could not parse CSS stylesheet for nested @media rule #833

Description

@danebenal

Component

design-system-react-components

Description

I'm running Vitest in a new application which is using design-system-react-components v0.8.1 and encountering the below error.

Error: Could not parse CSS stylesheet
    at exports.createStylesheet (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:37:21)
    at HTMLStyleElementImpl._updateAStyleBlock (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:67:5)
    at HTMLStyleElementImpl._childTextContentChangeSteps (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:35:12)
    at HTMLStyleElementImpl._insert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:823:14)
    at HTMLStyleElementImpl._preInsert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:757:10)
    at HTMLStyleElementImpl._append (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:863:17)
    at HTMLStyleElementImpl.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:599:17)
    at HTMLStyleElement.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js:411:60)
    at styleInject (file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/node_modules/style-inject/dist/style-inject.es.js:24:11)
    at file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/dist/esm/index.js:32061:1 .bcds-react-aria-ProgressBar {
  display: flex;
  flex-direction: column;
  gap: var(--layout-padding-xsmall);
  font: var(--typography-regular-small-body);
  color: var(--typography-color-primary);
}

/* Label */
.bcds-react-aria-ProgressBar--Label {
  display: flex;
  flex-direction: row;
  gap: var(--layout-margin-medium);
  justify-content: space-between;
}

.bcds-react-aria-ProgressBar--Value {
  color: var(--typography-color-secondary);
}

/* Structure */
.bcds-react-aria-ProgressBar--Track {
  position: relative;
  overflow: hidden;
  background-color: var(--surface-color-border-default);
  border: var(--layout-border-width-small) solid
    var(--surface-color-border-default);
  border-radius: var(--layout-border-radius-circular);
}
.bcds-react-aria-ProgressBar--Fill {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  background: var(--surface-color-primary-default);
  border-radius: var(--layout-border-radius-circular);
  width: 100%;
  transform-origin: left;
  transform: scaleX(var(--percentage));
  transition: transform 200ms linear;

  @media (prefers-reduced-motion: reduce) {
    animation: none;
  }
}

/* Sizing */
.bcds-react-aria-ProgressBar--Track.small {
  height: var(--layout-padding-hair);
}
.bcds-react-aria-ProgressBar--Track.medium {
  height: var(--layout-padding-xsmall);
}
.bcds-react-aria-ProgressBar--Track.large {
  height: var(--layout-padding-small);
}

/* Indeterminate animation */
.bcds-react-aria-ProgressBar:not([aria-valuenow])
  .bcds-react-aria-ProgressBar--Fill {
  background-color: var(--surface-color-primary-default);
  transform: scaleX(1);
  animation: indeterminate-bar 1.5s linear infinite;

  @media (prefers-reduced-motion: reduce) {
    animation: indeterminate-bar-pulse 2s ease-in-out infinite;
  }
}
@keyframes indeterminate-bar {
  0% {
    transform: translateX(-100%) scaleX(0.4);
  }
  50% {
    transform: translateX(0%) scaleX(0.4);
  }
  100% {
    transform: translateX(100%) scaleX(0.4);
  }
}
@keyframes indeterminate-bar-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

Error: Could not parse CSS stylesheet
    at exports.createStylesheet (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:37:21)
    at HTMLStyleElementImpl._updateAStyleBlock (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:67:5)
    at HTMLStyleElementImpl._childTextContentChangeSteps (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:35:12)
    at HTMLStyleElementImpl._insert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:823:14)
    at HTMLStyleElementImpl._preInsert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:757:10)
    at HTMLStyleElementImpl._append (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:863:17)
    at HTMLStyleElementImpl.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:599:17)
    at HTMLStyleElement.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js:411:60)
    at styleInject (file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/node_modules/style-inject/dist/style-inject.es.js:24:11)
    at file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/dist/esm/index.js:32070:1 .bcds-react-aria-ProgressCircle {
  display: flex;
  flex-direction: column;
  gap: var(--layout-padding-xsmall);
  font: var(--typography-regular-small-body);
  color: var(--typography-color-primary);
}

/* Label */
.bcds-react-aria-ProgressCircle--Label {
  display: flex;
  flex-direction: column;
  gap: var(--layout-margin-hair);
  align-items: center;
  justify-content: center;
}
.bcds-react-aria-ProgressCircle--Value {
  color: var(--typography-color-secondary);
}

/* Structure */
svg.bcds-react-aria-ProgressCircle--Container {
  display: flex;
  align-self: center;
  fill: none;
  width: 100%;
  height: 100%;
}
.bcds-react-aria-ProgressCircle--Track {
  cx: 50%;
  cy: 50%;
  stroke: var(--theme-gray-30);
}
.bcds-react-aria-ProgressCircle--Fill {
  cx: 50%;
  cy: 50%;
  stroke: var(--theme-primary-blue);
  stroke-dasharray: 100 200;
  stroke-linecap: round;
  rotate: -90deg;
  transform-origin: center center;
  transition: 200ms linear;
}

/* Sizing */
svg.bcds-react-aria-ProgressCircle--Container.small {
  width: var(--icons-size-medium);
  height: var(--icons-size-medium);
  stroke-width: var(--layout-border-width-medium);

  circle.bcds-react-aria-ProgressCircle--Track,
  circle.bcds-react-aria-ProgressCircle--Fill {
    r: calc(50% - var(--layout-border-width-medium) / 2);
  }
}
svg.bcds-react-aria-ProgressCircle--Container.medium {
  width: var(--icons-size-large);
  height: var(--icons-size-large);
  stroke-width: var(--layout-border-width-medium);

  circle.bcds-react-aria-ProgressCircle--Track,
  circle.bcds-react-aria-ProgressCircle--Fill {
    r: calc(50% - var(--layout-border-width-medium) / 2);
  }
}
svg.bcds-react-aria-ProgressCircle--Container.large {
  width: var(--icons-size-xlarge);
  height: var(--icons-size-xlarge);
  stroke-width: var(--layout-border-width-large);

  circle.bcds-react-aria-ProgressCircle--Track,
  circle.bcds-react-aria-ProgressCircle--Fill {
    r: calc(50% - var(--layout-border-width-large) / 2);
  }
}

/* Indeterminate animation */
.bcds-react-aria-ProgressCircle:not([aria-valuenow])
  .bcds-react-aria-ProgressCircle--Fill {
  animation: indeterminate 1.5s linear infinite;

  @media (prefers-reduced-motion: reduce) {
    animation: indeterminate-circle-pulse 2s ease-in-out infinite;
    stroke-dashoffset: 0;
  }
}

@keyframes indeterminate {
  from {
    rotate: -90deg;
  }
  to {
    rotate: 270deg;
  }
}
@keyframes indeterminate-circle-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

Error: Could not parse CSS stylesheet
    at exports.createStylesheet (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:37:21)
    at HTMLStyleElementImpl._updateAStyleBlock (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:67:5)
    at HTMLStyleElementImpl._childTextContentChangeSteps (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:35:12)
    at HTMLStyleElementImpl._insert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:823:14)
    at HTMLStyleElementImpl._preInsert (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:757:10)
    at HTMLStyleElementImpl._append (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:863:17)
    at HTMLStyleElementImpl.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:599:17)
    at HTMLStyleElement.appendChild (/home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js:411:60)
    at styleInject (file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/node_modules/style-inject/dist/style-inject.es.js:24:11)
    at file:///home/runner/work/icm-dq-recon-reporting/icm-dq-recon-reporting/frontend/node_modules/@bcgov/design-system-react-components/dist/esm/index.js:32236:1 .bcds-react-aria-ToggleButton {
  display: inline-flex;
  flex: 0 1 auto;
  flex-direction: row;
  flex-wrap: wrap;
  white-space: normal;
  box-sizing: border-box;
  gap: var(--layout-margin-xsmall);
  align-items: center;
  justify-content: center;
  padding: var(--layout-padding-hair) var(--layout-padding-small);
  color: var(--typography-color-secondary);
  background-color: var(--surface-color-secondary-button-disabled);
  border: var(--layout-border-width-small) solid transparent;
  border-radius: var(--layout-border-radius-medium);
  cursor: pointer;
}

/* Size */
.bcds-react-aria-ToggleButtonGroup.small > .bcds-react-aria-ToggleButton,
.bcds-react-aria-ToggleButton.small {
  font: var(--typography-regular-small-body);
}

.bcds-react-aria-ToggleButtonGroup.medium > .bcds-react-aria-ToggleButton,
.bcds-react-aria-ToggleButton.medium {
  font: var(--typography-regular-body);
}

/* Icon button */
.bcds-react-aria-ToggleButton.icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

.bcds-react-aria-ToggleButton.icon > * {
  line-height: 0;
}

.bcds-react-aria-ToggleButton.small.icon {
  padding: unset;
  height: var(--icons-size-large);
  width: var(--icons-size-large);
  min-width: var(--icons-size-large);
}

.bcds-react-aria-ToggleButton.medium.icon {
  padding: unset;
  height: var(--icons-size-xlarge);
  width: var(--icons-size-xlarge);
  min-width: var(--icons-size-xlarge);
}

/* Active */
.bcds-react-aria-ToggleButton[data-selected] {
  background-color: var(--surface-color-secondary-button-default);
  color: var(--typography-color-primary);
  border: var(--layout-border-width-small) solid
    var(--surface-color-secondary-button-default);
  box-shadow: var(--surface-shadow-small);
  /* Animate transition on select or deselect */
  transition: 200ms ease;

  @media (prefers-reduced-motion: reduce) {
    transition: none;
  }
}

/* Hover */
.bcds-react-aria-ToggleButton[data-hovered] {
  background-color: var(--surface-color-secondary-pressed);
  color: var(--typography-color-primary);
  border: var(--layout-border-width-small) solid
    var(--surface-color-border-medium);
  border-radius: var(--layout-border-radius-medium);
}
/* Focused */
.bcds-react-aria-ToggleButton[data-focus-visible] {
  background-color: var(--theme-blue-10);
  outline: var(--layout-border-width-medium) solid
    var(--surface-color-border-active);
}

/* Pressed */
.bcds-react-aria-ToggleButton[data-hovered][data-pressed] {
  background-color: var(--theme-gray-20);
  border: var(--layout-border-width-small) solid var(--theme-gray-20);
}

/* Disabled */
.bcds-react-aria-ToggleButton[data-disabled] {
  color: var(--typography-color-disabled);
  cursor: not-allowed;
  /* Animate transition on disable or enable */
  transition: 200ms ease;

  @media (prefers-reduced-motion: reduce) {
    transition: none;
  }
}

Steps to reproduce

Running vitest:

vitest run

Copilot advises

Minimal reproduction:

import '@bcgov/design-system-react-components';

test('loads the design system', () => {
  expect(true).toBe(true);
});

The warning appears when the dependency injects its CSS into a jsdom
<style> element. Browser builds and the application runtime do not show this
problem.

and

The nested @media rule is the most likely trigger in the output, although the jsdom maintainers can confirm the exact unsupported grammar

Technical information

This doesn't appear to be viewable in browsers, only through test suites (at least vitest)

Environment:

  • OS: Windows 11
  • Node.js: 26.7.0
  • npm: 11.19.0
  • jsdom: 30.0.1
  • Vitest: 4.1.10
  • Vite: 8.2.1
  • @vitejs/plugin-react: 6.0.5
  • @bcgov/design-system-react-components: 0.8.1
  • React: 19.2.8
  • @testing-library/jest-dom: 7.0.1
  • @testing-library/react: 16.3.2
  • @types/react: 19.2.18
  • @types/react-dom: 19.2.4

Note that when I was using an older versions of these libraries, I saw the stacktrace I included in the Description. After upgrading to the latest versions, I only see

Could not parse CSS stylesheet repeated three times

logs_before-upgrade.zip
logs_after-upgrade.zip

Metadata

Metadata

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions