Content
diff --git a/src/components/provider/provider.test.tsx b/src/components/provider/provider.test.tsx
index 84fc7a9c96e..0f61e2d61e2 100644
--- a/src/components/provider/provider.test.tsx
+++ b/src/components/provider/provider.test.tsx
@@ -66,14 +66,22 @@ describe('EuiProvider', () => {
) as HTMLStyleElement;
};
- it('uses a default cache from Emotion when configured without a cache', () => {
- render(
);
+ it('uses a default fallback cache with EUI prefixing when one is not passed', () => {
+ render(
+
+
+
+ );
expect(emotionCache.key).toEqual('css');
expect(getStyleByCss('html').dataset.emotion).toEqual('css-global');
expect(getStyleByCss('.eui-displayBlock').dataset.emotion).toEqual(
'css-global'
);
+ // The below CSS would have prefixes if the default `@emotion/css` cache were used
+ expect(getStyleByCss('test-no-cache').textContent).toMatchInlineSnapshot(
+ `".css-1b3dqg7-test-no-cache{display:flex;}"`
+ );
});
it('applies the cache to all styles', () => {
diff --git a/src/components/provider/provider.tsx b/src/components/provider/provider.tsx
index c9e39613e70..69403787511 100644
--- a/src/components/provider/provider.tsx
+++ b/src/components/provider/provider.tsx
@@ -7,13 +7,8 @@
*/
import React, { PropsWithChildren } from 'react';
-import { cache as fallbackCache, EmotionCache } from '@emotion/css';
+import type { EmotionCache } from '@emotion/css';
-import {
- EuiGlobalStyles,
- EuiGlobalStylesProps,
-} from '../../global_styling/reset/global_styles';
-import { EuiUtilityClasses } from '../../global_styling/utility/utility';
import {
EuiThemeProvider,
EuiThemeProviderProps,
@@ -21,7 +16,15 @@ import {
CurrentEuiBreakpointProvider,
} from '../../services';
import { emitEuiProviderWarning } from '../../services/theme/warning';
+import { cache as fallbackCache } from '../../services/emotion/css';
+
+import {
+ EuiGlobalStyles,
+ EuiGlobalStylesProps,
+} from '../../global_styling/reset/global_styles';
+import { EuiUtilityClasses } from '../../global_styling/utility/utility';
import { EuiThemeAmsterdam } from '../../themes';
+
import { EuiCacheProvider } from './cache';
import { EuiProviderNestedCheck, useIsNestedEuiProvider } from './nested';
import {
diff --git a/src/services/emotion/css.test.ts b/src/services/emotion/css.test.ts
new file mode 100644
index 00000000000..2e2bab76422
--- /dev/null
+++ b/src/services/emotion/css.test.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { css, cx } from './css';
+
+describe('custom EUI Emotion instance', () => {
+ it("creates a vanilla JS className that contains styles with EUI's custom configuration", () => {
+ const test = css`
+ display: flex;
+ `;
+ expect(test).toEqual('css-vyoujf');
+
+ // Should not have any extra browser prefixes, per EUI's configuration
+ const styleOutput = document.head.querySelector('style[data-emotion]')!;
+ expect(styleOutput.textContent).toEqual('.css-vyoujf{display:flex;}');
+ });
+
+ // NOTE: Currently, custom Emotion instances do *not* merge css auto labels
+ // @see https://github.com/emotion-js/emotion/issues/3113
+ it('correctly merges css with labels', () => {
+ const test1 = css`
+ label: hello;
+ color: red;
+ `;
+ const test2 = css`
+ label: world;
+ background-color: blue;
+ `;
+ expect(cx(test1, test2)).toEqual('css-4dyepw-hello-world');
+ });
+});
diff --git a/src/services/emotion/css.ts b/src/services/emotion/css.ts
new file mode 100644
index 00000000000..0c3193996bf
--- /dev/null
+++ b/src/services/emotion/css.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import createEmotion from '@emotion/css/create-instance';
+
+import { euiStylisPrefixer } from './prefixer';
+
+/**
+ * This custom instance is needed for internal EUI components to call
+ * `@emotion/css` with EUI's custom prefixer plugin
+ * @see https://emotion.sh/docs/@emotion/css#custom-instances
+ *
+ * NOTE: Usage is currently being beta tested internally,
+ * and is not yet intended to be a public export
+ */
+export const { css, cx, cache } = createEmotion({
+ key: 'css',
+ stylisPlugins: [euiStylisPrefixer],
+ speedy: false,
+});
diff --git a/src/services/emotion/index.ts b/src/services/emotion/index.ts
index d7a50a60227..2fb45487285 100644
--- a/src/services/emotion/index.ts
+++ b/src/services/emotion/index.ts
@@ -7,3 +7,4 @@
*/
export * from './clone_element';
+export * from './prefixer';
diff --git a/src/services/emotion/prefixer.test.tsx b/src/services/emotion/prefixer.test.tsx
new file mode 100644
index 00000000000..867e611290e
--- /dev/null
+++ b/src/services/emotion/prefixer.test.tsx
@@ -0,0 +1,567 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React, { FunctionComponent, PropsWithChildren } from 'react';
+import { render } from '@testing-library/react';
+import { css, keyframes } from '@emotion/react';
+import { cache as defaultEmotionCache } from '@emotion/css';
+import createCache from '@emotion/cache';
+
+import { EuiProvider } from '../../components/provider';
+
+import { euiStylisPrefixer } from './prefixer';
+
+describe('euiStylisPrefixer', () => {
+ const cacheWithPrefixer = createCache({
+ key: 'test',
+ stylisPlugins: [euiStylisPrefixer],
+ });
+
+ const wrapper: FunctionComponent
= ({ children }) => (
+
+ {children}
+
+ );
+
+ const getStyleCss = (label: string) => {
+ const styleEl = Array.from(
+ document.querySelectorAll('style[data-emotion]')
+ ).find((el) => el?.textContent?.includes(label)) as HTMLStyleElement;
+ if (!styleEl) return;
+
+ // Make output styles a little easier to read
+ return styleEl
+ .textContent!.replace('{', ' {\n')
+ .replace(/;/g, ';\n')
+ .replace(/:/g, ': ');
+ };
+
+ describe('does prefix', () => {
+ test('user-select', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('user-select')).toMatchInlineSnapshot(`
+ ".test-8c1x7t-user-select {
+ -webkit-user-select: none;
+ user-select: none;
+ }"
+ `);
+ });
+
+ test('text-decoration', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('text-decoration')).toMatchInlineSnapshot(`
+ ".test-5idn3j-text-decoration {
+ -webkit-text-decoration: line-through dashed blue;
+ text-decoration: line-through dashed blue;
+ text-decoration-line: underline overline;
+ text-decoration-style: wavy;
+ text-decoration-color: red;
+ text-decoration-skip: objects;
+ }"
+ `);
+ });
+
+ test('text-size-adjust', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('text-size-adjust')).toMatchInlineSnapshot(`
+ ".test-15dfadm {
+ -webkit-text-size-adjust: 80%;
+ text-size-adjust: 80%;
+ }"
+ `);
+ });
+
+ test('box-decoration-break', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('box-decoration-break')).toMatchInlineSnapshot(`
+ ".test-m64wfr-box-decoration-break {
+ -webkit-box-decoration-break: slice;
+ box-decoration-break: slice;
+ }"
+ `);
+ });
+
+ describe('mask CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('mask-css')).toMatchInlineSnapshot(`
+ ".test-16l1rpr-mask-css {
+ -webkit-mask: url(mask.svg);
+ mask: url(mask.svg);
+ -webkit-mask-image: linear-gradient(rgba(0, 0, 0, 1), transparent);
+ mask-image: linear-gradient(rgba(0, 0, 0, 1), transparent);
+ -webkit-mask-clip: border-box;
+ mask-clip: border-box;
+ -webkit-mask-origin: padding-box;
+ mask-origin: padding-box;
+ -webkit-mask-composite: subtract;
+ mask-composite: subtract;
+ -webkit-mask-mode: alpha;
+ mask-mode: alpha;
+ -webkit-mask-position: center;
+ mask-position: center;
+ -webkit-mask-repeat: repeat-x;
+ mask-repeat: repeat-x;
+ -webkit-mask-size: contain;
+ mask-size: contain;
+ }"
+ `);
+ });
+
+ test('background-clip text', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('background-clip')).toMatchInlineSnapshot(`
+ ".test-9vijyk-background-clip {
+ background-clip: content-box;
+ -webkit-background-clip: text;
+ background-clip: text;
+ }"
+ `);
+ });
+
+ test('print-color-adjust', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('print-color-adjust')).toMatchInlineSnapshot(`
+ ".test-cx4oo-print-color-adjust {
+ -webkit-print-color-adjust: economy;
+ print-color-adjust: economy;
+ }"
+ `);
+ });
+
+ test('max-content, min-content, fit-content, and stretch sizing values', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('intrinsic-extrensic-sizing')).toMatchInlineSnapshot(`
+ ".test-tsfq3u-intrinsic-extrensic-sizing {
+ height: max-content;
+ width: min-content;
+ max-inline-size: fit-content;
+ min-block-size: -webkit-fill-available;
+ min-block-size: -moz-available;
+ min-block-size: stretch;
+ }"
+ `);
+ });
+ });
+
+ describe('does not prefix', () => {
+ test('flex CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-flex-prefixes')).toMatchInlineSnapshot(`
+ ".test-1467bft-no-flex-prefixes {
+ display: flex;
+ display: inline-flex;
+ align-items: center;
+ align-content: center;
+ align-self: center;
+ justify-content: center;
+ flex-shrink: 0;
+ flex-grow: 0;
+ flex-basis: 100%;
+ flex: 1;
+ flex-direction: column;
+ order: 2;
+ }"
+ `);
+ });
+
+ test('transform & transition CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-transform-prefixes')).toMatchInlineSnapshot(`
+ ".test-1oc6c8-no-transform-prefixes {
+ transform: translateY(-1px);
+ transition: transform 2s linear;
+ }"
+ `);
+ });
+
+ test('animation CSS', () => {
+ const testAnimation = keyframes`
+ from { opacity: 0; }
+ to { opacity: 1; }
+ `;
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-animation-prefixes')).toMatchInlineSnapshot(`
+ ".test-1aw2200-no-animation-prefixes {
+ animation: animation-1flhruc;
+ animation-name: test;
+ animation-delay: 1s;
+ animation-direction: reverse;
+ animation-duration: 50ms;
+ animation-fill-mode: both;
+ animation-iteration-count: infinite;
+ animation-play-state: paused;
+ animation-timing-function: ease-in-out;
+ }"
+ `);
+ expect(getStyleCss('@keyframes')).toBeTruthy();
+ expect(getStyleCss('@-webkit-keyframes')).toBeFalsy();
+ });
+
+ test('position sticky', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-position-sticky-prefix')).toMatchInlineSnapshot(`
+ ".test-11x1k54-no-position-sticky-prefix {
+ position: sticky;
+ }"
+ `);
+ });
+
+ test('writing mode CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-writing-mode-prefixes')).toMatchInlineSnapshot(`
+ ".test-1d4iba8-no-writing-mode-prefixes {
+ writing-mode: vertical-lr;
+ writing-mode: vertical-rl;
+ writing-mode: horizontal-tb;
+ }"
+ `);
+ });
+
+ test('inline logical properties CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('no-logical-properties-prefixes'))
+ .toMatchInlineSnapshot(`
+ ".test-11697m3-no-logical-properties-prefixes {
+ padding-inline-start: 1rem;
+ margin-inline-end: 2em;
+ }"
+ `);
+ });
+
+ test('columns CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-columns-prefixes')).toMatchInlineSnapshot(`
+ ".test-1eossg4-no-columns-prefixes {
+ columns: 3;
+ column-count: 5;
+ column-fill: balance;
+ column-gap: 10px;
+ column-width: 20px;
+ column-span: all;
+ column-rule: blue dotted 2px;
+ }"
+ `);
+ });
+
+ test('misc text effect CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+ expect(getStyleCss('no-misc-text-effect-prefixes'))
+ .toMatchInlineSnapshot(`
+ ".test-29xaas-no-misc-text-effect-prefixes {
+ appearance: none;
+ hyphens: auto;
+ cursor: grab;
+ }"
+ `);
+ });
+
+ test('misc filter/effect/image CSS', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('no-filter-prefixes')).toMatchInlineSnapshot(`
+ ".test-8ziglt-no-filter-prefixes {
+ filter: grayscale(1);
+ clip-path: url(#foo);
+ backface-visibility: visible;
+ background: image-set(
+ linear-gradient(blue, white) 1x,
+ linear-gradient(blue, green) 2x
+ );
+ }"
+ `);
+ });
+
+ test('misc selectors', () => {
+ render(
+ ,
+ { wrapper }
+ );
+
+ expect(getStyleCss('::-moz-placeholder')).toBeFalsy();
+ expect(getStyleCss(':-moz-read-only')).toBeFalsy();
+ expect(getStyleCss(':-moz-read-write')).toBeFalsy();
+ });
+ });
+
+ describe('default Emotion cache', () => {
+ it('prefixes extra CSS that the EUI plugin does not', () => {
+ render(
+
+
+
+ );
+
+ expect(getStyleCss('test-default-cache')).toMatchInlineSnapshot(`
+ ".css-tfft1m-test-default-cache {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-padding-start: 1rem;
+ padding-inline-start: 1rem;
+ -webkit-margin-end: 2em;
+ margin-inline-end: 2em;
+ -webkit-animation: something;
+ animation: something;
+ -webkit-transform: translateY(-1px);
+ -moz-transform: translateY(-1px);
+ -ms-transform: translateY(-1px);
+ transform: translateY(-1px);
+ -webkit-transition: -webkit-transform 2s linear;
+ transition: transform 2s linear;
+ position: -webkit-sticky;
+ position: sticky;
+ -webkit-writing-mode: vertical-rl;
+ -ms-writing-mode: tb-rl;
+ writing-mode: vertical-rl;
+ -webkit-column-count: 2;
+ column-count: 2;
+ block-size: -webkit-max-content;
+ block-size: -moz-max-content;
+ block-size: max-content;
+ -webkit-filter: blur(5px);
+ filter: blur(5px);
+ cursor: -webkit-grab;
+ cursor: grab;
+ }"
+ `);
+ expect(getStyleCss('::-moz-placeholder')).toBeTruthy();
+ });
+ });
+});
diff --git a/src/services/emotion/prefixer.ts b/src/services/emotion/prefixer.ts
new file mode 100644
index 00000000000..c1c6259c5a4
--- /dev/null
+++ b/src/services/emotion/prefixer.ts
@@ -0,0 +1,120 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import {
+ charat,
+ DECLARATION,
+ hash,
+ indexof,
+ MOZ,
+ replace,
+ strlen,
+ WEBKIT,
+ type Element,
+} from 'stylis';
+
+// This is a heavily modified version of Emotion's default `prefixer` plugin
+// (mostly removing unnecessary prefixes), which is in turn a modified version
+// of stylis's default prefixer.
+// @see https://github.com/emotion-js/emotion/blob/main/packages/cache/src/prefixer.js
+/* eslint-disable prefer-template */
+
+/**
+ * This is a stylis plugin which handles auto-prefixing CSS output by Emotion.
+ *
+ * *Please note*: EUI/Elastic targets latest evergreen browsers for support only.
+ * @see https://www.elastic.co/support/matrix#matrix_browsers
+ */
+export const euiStylisPrefixer = (element: Element) => {
+ if (element.length > -1)
+ if (!element.return)
+ switch (element.type) {
+ case DECLARATION:
+ element.return = prefix(element.value, element.length);
+ break;
+ }
+};
+
+const prefix = (value: Element['value'], length: Element['length']): string => {
+ switch (hash(value, length)) {
+ /**
+ * `-webkit` prefixes
+ */
+ // user-select - https://caniuse.com/mdn-css_properties_user-select - needed by Safari
+ case 4246:
+ // text-decoration - https://caniuse.com/text-decoration - iOS Safari is the main one that needs this
+ case 5572:
+ // text-size-adjust - https://caniuse.com/text-size-adjust - iOS Safari
+ case 2756:
+ // box-decoration-break - https://caniuse.com/css-boxdecorationbreak - Chrome & Safari
+ case 3005:
+ // mask, mask-image, mask-(mode|clip|size), mask-(repeat|origin), mask-position, mask-composite - Chrome
+ case 6391:
+ case 5879:
+ case 5623:
+ case 6135:
+ case 4599:
+ case 4855:
+ // print-color-adjust - https://caniuse.com/css-color-adjust - Chrome
+ case 2282:
+ return WEBKIT + value + value;
+
+ // background-clip - https://caniuse.com/background-clip-text - Chrome, only for `text` value
+ case 4215:
+ if (~indexof(value, 'text')) {
+ return WEBKIT + value + value;
+ }
+
+ /**
+ * Intrinsic/extrinsic sizing value prefixes
+ * `stretch` alternatives needed by Chrome & Firefox - https://caniuse.com/intrinsic-width
+ */
+ // (min|max)?(width|height|inline-size|block-size)
+ case 8116:
+ case 7059:
+ case 5753:
+ case 5535:
+ case 5445:
+ case 5701:
+ case 4933:
+ case 4677:
+ case 5533:
+ case 5789:
+ case 5021:
+ case 4765:
+ // stretch, max-content, min-content, fill-available
+ if (strlen(value) - 1 - length > 6)
+ switch (charat(value, length + 1)) {
+ // (f)ill-available
+ case 102:
+ if (~indexof(value, 'fill-available')) {
+ return replace(
+ value,
+ /(.+:)(.+)-([^]+)/,
+ '$1' +
+ WEBKIT +
+ '$2-$3' +
+ '$1' +
+ MOZ +
+ (charat(value, length + 3) === 108 ? '$3' : '$2-$3')
+ );
+ }
+ // (s)tretch
+ case 115:
+ if (~indexof(value, 'stretch')) {
+ return (
+ prefix(replace(value, 'stretch', 'fill-available'), length) +
+ value
+ );
+ }
+ }
+ break;
+ }
+
+ return value;
+};
diff --git a/src/services/theme/__snapshots__/provider.test.tsx.snap b/src/services/theme/__snapshots__/provider.test.tsx.snap
index 47336d01d76..5d8598c2489 100644
--- a/src/services/theme/__snapshots__/provider.test.tsx.snap
+++ b/src/services/theme/__snapshots__/provider.test.tsx.snap
@@ -2,7 +2,7 @@
exports[`EuiThemeProvider CSS variables allows child components to set non-global theme CSS variables 1`] = `
`;
@@ -11,7 +11,7 @@ exports[`EuiThemeProvider nested EuiThemeProviders allows avoiding the extra spa
Top-level provider
clone provider color onto div
@@ -23,7 +23,7 @@ exports[`EuiThemeProvider nested EuiThemeProviders allows customizing the span w
Top-level provider
Nested
@@ -36,15 +36,15 @@ exports[`EuiThemeProvider nested EuiThemeProviders renders with a span wrapper t
Top-level provider
Nested
Double nested
Triple nested
diff --git a/src/services/theme/provider.tsx b/src/services/theme/provider.tsx
index 0005f356d9f..76fab79de5b 100644
--- a/src/services/theme/provider.tsx
+++ b/src/services/theme/provider.tsx
@@ -16,13 +16,12 @@ import React, {
PropsWithChildren,
HTMLAttributes,
} from 'react';
-import classNames from 'classnames';
-import { css } from '@emotion/css';
import { Global, type CSSObject } from '@emotion/react';
import isEqual from 'lodash/isEqual';
import type { CommonProps } from '../../components/common';
import { cloneElementWithCss } from '../emotion';
+import { css, cx } from '../emotion/css';
import {
EuiSystemContext,
@@ -160,7 +159,7 @@ export const EuiThemeProvider = ({
? false
: bodyColor !== theme.colors.text,
colorClassName: css`
- label: euiColorMode-${_colorMode};
+ label: euiColorMode-${_colorMode || colorMode};
color: ${theme.colors.text};
`,
setGlobalCSSVariables: isGlobalTheme
@@ -177,6 +176,7 @@ export const EuiThemeProvider = ({
isGlobalTheme,
bodyColor,
_colorMode,
+ colorMode,
setGlobalCSSVariables,
globalCSSVariables,
setThemeCSSVariables,
@@ -191,7 +191,7 @@ export const EuiThemeProvider = ({
const { cloneElement, className, ...rest } = wrapperProps || {};
const props = {
...rest,
- className: classNames(className, nestedThemeContext.colorClassName),
+ className: cx(className, nestedThemeContext.colorClassName),
};
// Condition avoids rendering an empty Emotion selector if no
// theme-specific CSS variables have been set by child components
@@ -202,14 +202,11 @@ export const EuiThemeProvider = ({
if (cloneElement) {
return cloneElementWithCss(children, {
...props,
- className: classNames(children.props.className, props.className),
+ className: cx(children.props.className, props.className),
});
} else {
return (
-
+
{children}
);
diff --git a/src/services/theme/utils.ts b/src/services/theme/utils.ts
index 089f985a6ee..c7c9c5216d0 100644
--- a/src/services/theme/utils.ts
+++ b/src/services/theme/utils.ts
@@ -39,7 +39,7 @@ export const isInverseColorMode = (
/**
* Returns the color mode configured in the current EuiThemeProvider.
* Returns the parent color mode if none is explicity set.
- * @param {string} coloMode - `light`, `dark`, or `inverse`
+ * @param {string} colorMode - `light`, `dark`, or `inverse`
* @param {string} parentColorMode - `LIGHT` or `DARK`; used as the fallback
*/
export const getColorMode = (
diff --git a/upcoming_changelogs/7272.md b/upcoming_changelogs/7272.md
new file mode 100644
index 00000000000..021502d52d9
--- /dev/null
+++ b/upcoming_changelogs/7272.md
@@ -0,0 +1,3 @@
+**CSS-in-JS conversions**
+
+- Reduced default CSS prefixes generated by Emotion to only browsers supported by EUI (latest evergreen browsers). This can be customized by passing your own Emotion cache to `EuiProvider`.
diff --git a/yarn.lock b/yarn.lock
index 895eec82a7d..b811b178a9d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5219,6 +5219,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
+"@types/stylis@^4.2.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.1.tgz#867fcb0f81719d9ecef533fdda03e32083b959f6"
+ integrity sha512-OSaMrXUKxVigGlKRrET39V2xdhzlztQ9Aqumn1WbCBKHOi9ry7jKSd7rkyj0GzmWaU960Rd+LpOFpLfx5bMQAg==
+
"@types/testing-library__jest-dom@^5.14.3", "@types/testing-library__jest-dom@^5.9.1":
version "5.14.5"
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f"