Repository: elastic/eui (TypeScript)

Issue:
Support specifying `_FontScaleOptions` globally
**Is your feature request related to a problem? Please describe.**

I'm currently developing a browser extension. In my extension, I use Shadow DOM to isolate styles to ensure my extensions render correctly in various web environments. However, I've run into an issue that I hope can be improved.
The problem is that, due to the inability to globally specify the `_FontScaleOptions` of the [`euiFontSize`](https://github.com/elastic/eui/blob/main/src/global_styling/mixins/_typography.ts) method, the `font-size` of some components uses `rem` units by default (<https://github.com/elastic/eui/blob/main/src/components/tabs/tab.styles.ts>). This caused my extension to not render correctly on some webpages with <html> font sizes set.




Discussion: Labeling this as high priority and low effort. We think this would be a quick win so plan to address this shortly.
Thank you for the issue submission @y1j2x34. The EUI team is working on this in a related pull request.



Fix (patch):
diff --git a/src-docs/src/views/theme/typography/_typography_js.tsx b/src-docs/src/views/theme/typography/_typography_js.tsx
index c54793b46a2..354c7c5bd34 100644
--- a/src-docs/src/views/theme/typography/_typography_js.tsx
+++ b/src-docs/src/views/theme/typography/_typography_js.tsx
@@ -1,6 +1,6 @@
 import React, { FunctionComponent, useState } from 'react';
 import { css } from '@emotion/react';
-import { useEuiTheme } from '../../../../../src/services';
+import { useEuiTheme, EuiThemeProvider } from '../../../../../src/services';
 import {
   EuiBasicTable,
   EuiButtonGroup,
@@ -9,6 +9,7 @@ import {
   EuiDescribedFormGroup,
   EuiPanel,
   EuiSpacer,
+  EuiText,
 } from '../../../../../src/components';
 
 import {
@@ -16,8 +17,8 @@ import {
   useEuiFontSize,
   EuiThemeFontWeights,
   EuiThemeFontScales,
-  EuiThemeFontSizeMeasurements,
-  _EuiThemeFontSizeMeasurement,
+  EuiThemeFontUnits,
+  _EuiThemeFontUnit,
 } from '../../../../../src/global_styling';
 
 import { EuiThemeFontBase, EuiThemeFontWeight, ThemeRowType } from '../_props';
@@ -104,6 +105,26 @@ export const FontJS = () => {
         snippet={'font-feature-settings: ${euiTheme.font.featureSettings};'}
         snippetLanguage="emotion"
       />
+
+      <ThemeExample
+        title={<code>euiTheme.font.defaultUnits</code>}
+        description={getDescription(baseProps.defaultUnits)}
+        example={
+          <EuiThemeProvider modify={{ font: { defaultUnits: 'px' } }}>
+            <EuiText>
+              My font size and line height is set using <EuiCode>px</EuiCode>{' '}
+              and not <EuiCode>rem</EuiCode>
+            </EuiText>
+          </EuiThemeProvider>
+        }
+        snippet={`<EuiProvider modify={{ font: { defaultUnits: 'px' } }}>
+  <EuiText>
+    <p>Hello world</p>
+  </EuiText>
+</EuiProvider>
+`}
+        snippetLanguage="jsx"
+      />
     </>
   );
 };
@@ -229,27 +250,25 @@ export const FontScaleValuesJS = () => {
   const euiThemeContext = useEuiTheme();
   const scaleKeys = EuiThemeFontScales;
 
-  const measurementButtons = EuiThemeFontSizeMeasurements.map((m) => {
+  const unitButtons = EuiThemeFontUnits.map((m) => {
     return {
       id: m,
       label: m,
     };
   });
 
-  const [measurementSelected, setMeasurementSelected] = useState(
-    measurementButtons[0].id
-  );
+  const [unitSelected, setUnitSelected] = useState(unitButtons[0].id);
 
   return (
     <>
       <EuiPanel color="accent">
         <EuiDescribedFormGroup
           fullWidth
-          title={<h3>Value measurements</h3>}
+          title={<h3>Font units</h3>}
           description={
             <p>
-              The font sizing function also supports the three main measurements
-              for font-size, <EuiCode>rem | px | em</EuiCode>, with{' '}
+              The font sizing function also supports three main units for font
+              size and line height: <EuiCode>rem | px | em</EuiCode>, with{' '}
               <EuiCode>rem</EuiCode> being default for all EUI components.
             </p>
           }
@@ -257,12 +276,10 @@ export const FontScaleValuesJS = () => {
           <EuiSpacer />
           <EuiButtonGroup
             buttonSize="m"
-            legend="Value measurement to show in table"
-            options={measurementButtons}
-            idSelected={measurementSelected}
-            onChange={(id) =>
-              setMeasurementSelected(id as _EuiThemeFontSizeMeasurement)
-            }
+            legend="Value unit to show in table"
+            options={unitButtons}
+            idSelected={unitSelected}
+            onChange={(id) => setUnitSelected(id as _EuiThemeFontUnit)}
             color="accent"
             isFullWidth
           />
@@ -272,23 +289,17 @@ export const FontScaleValuesJS = () => {
       <EuiBasicTable<FontScaleDetails>
         tableLayout="auto"
         items={scaleKeys.map((scale, index) => {
+          const { fontSize, lineHeight } = euiFontSize(euiThemeContext, scale, {
+            unit: unitSelected,
+          });
+
           return {
             id: scale,
             value: `useEuiFontSize('${scale}'${
-              measurementSelected !== 'rem'
-                ? `,\n  { measurement: '${measurementSelected}' }\n`
-                : ''
+              unitSelected !== 'rem' ? `, { unit: '${unitSelected}' }` : ''
             })`,
-            size: `${
-              euiFontSize(euiThemeContext, scale, {
-                measurement: measurementSelected,
-              }).fontSize
-            }`,
-            lineHeight: `${
-              euiFontSize(euiThemeContext, scale, {
-                measurement: measurementSelected,
-              }).lineHeight
-            }`,
+            size: String(fontSize),
+            lineHeight: String(lineHeight),
             index,
           };
         })}
@@ -302,7 +313,7 @@ export const FontScaleValuesJS = () => {
               <div
                 css={css`
                   ${euiFontSize(euiThemeContext, item.id, {
-                    measurement: measurementSelected,
+                    unit: unitSelected,
                   })}
                 `}
               >
diff --git a/src/components/markdown_editor/markdown_format.styles.ts b/src/components/markdown_editor/markdown_format.styles.ts
index 0def45152a3..c57fb005b3a 100644
--- a/src/components/markdown_editor/markdown_format.styles.ts
+++ b/src/components/markdown_editor/markdown_format.styles.ts
@@ -24,8 +24,8 @@ const euiScaleMarkdownFormatText = (
   options: _FontScaleOptions
 ) => {
   const { fontSize, lineHeight } = euiFontSize(euiTheme, 'm', options);
-  const { measurement } = options;
-  const lineHeightSize = measurement === 'em' ? `${lineHeight}em` : lineHeight;
+  const { unit } = options;
+  const lineHeightSize = unit === 'em' ? `${lineHeight}em` : lineHeight;
 
   // Custom scales
   const tablePaddingVertical = mathWithUnits(fontSize, (x) => x / 4);
@@ -67,25 +67,22 @@ export const euiMarkdownFormatStyles = (euiTheme: UseEuiTheme) => ({
   // Text sizes
   m: css`
     ${euiScaleMarkdownFormatText(euiTheme, {
-      measurement: 'rem',
       customScale: 'm',
     })}
   `,
   s: css`
     ${euiScaleMarkdownFormatText(euiTheme, {
-      measurement: 'rem',
       customScale: 's',
     })}
   `,
   xs: css`
     ${euiScaleMarkdownFormatText(euiTheme, {
-      measurement: 'rem',
       customScale: 'xs',
     })}
   `,
   relative: css`
     ${euiScaleMarkdownFormatText(euiTheme, {
-      measurement: 'em',
+      unit: 'em',
     })}
   `,
 });
diff --git a/src/components/text/text.styles.ts b/src/components/text/text.styles.ts
index 568d07293d5..0bcc68b2c45 100644
--- a/src/components/text/text.styles.ts
+++ b/src/components/text/text.styles.ts
@@ -46,8 +46,8 @@ const euiScaleText = (
 ) => {
   const { fontSize, lineHeight } = euiFontSize(euiThemeContext, 'm', options);
   const { euiTheme } = euiThemeContext;
-  const { measurement, customScale: _customScale } = options;
-  const lineHeightSize = measurement === 'em' ? `${lineHeight}em` : lineHeight;
+  const { unit, customScale: _customScale } = options;
+  const lineHeightSize = unit === 'em' ? `${lineHeight}em` : lineHeight;
 
   const headings = {
     h1: euiTitle(euiThemeContext, 'l', options),
@@ -345,25 +345,22 @@ export const euiTextStyles = (euiThemeContext: UseEuiTheme) => {
     // Sizes
     m: css`
       ${euiScaleText(euiThemeContext, {
-        measurement: 'rem',
         customScale: 'm',
       })}
     `,
     s: css`
       ${euiScaleText(euiThemeContext, {
-        measurement: 'rem',
         customScale: 's',
       })}
     `,
     xs: css`
       ${euiScaleText(euiThemeContext, {
-        measurement: 'rem',
         customScale: 'xs',
       })}
     `,
     relative: css`
       ${euiScaleText(euiThemeContext, {
-        measurement: 'em',
+        unit: 'em',
       })}
     `,
   };
diff --git a/src/global_styling/functions/typography.ts b/src/global_styling/functions/typography.ts
index cfff01e4772..1079febb407 100644
--- a/src/global_styling/functions/typography.ts
+++ b/src/global_styling/functions/typography.ts
@@ -8,7 +8,7 @@
 
 import {
   _EuiThemeFontScale,
-  _EuiThemeFontSizeMeasurement,
+  _EuiThemeFontUnit,
   _EuiThemeFontWeights,
 } from '../variables/typography';
 import { UseEuiTheme } from '../../services/theme/hooks';
@@ -16,9 +16,9 @@ import { logicalCSS } from './logicals';
 
 export interface _FontScaleOptions {
   /**
-   * The returned string measurement
+   * The font-size or line-height unit to return
    */
-  measurement?: _EuiThemeFontSizeMeasurement;
+  unit?: _EuiThemeFontUnit;
   /**
    * An additional custom scale multiplier to use against the current scale
    * This parameter can be used (e.g. by EuiText sizes) to get sizes of text smaller than the default
@@ -38,9 +38,9 @@ export interface _FontScaleOptions {
 export function euiFontSizeFromScale(
   scale: _EuiThemeFontScale,
   { base, font }: UseEuiTheme['euiTheme'],
-  { measurement = 'rem', customScale }: _FontScaleOptions = {}
+  { unit = font.defaultUnits, customScale }: _FontScaleOptions = {}
 ) {
-  if (measurement === 'em') {
+  if (unit === 'em') {
     return `${font.scale[scale]}em`;
   }
 
@@ -48,7 +48,7 @@ export function euiFontSizeFromScale(
   if (customScale) numerator *= font.scale[customScale];
   const denominator = base * font.scale[font.body.scale];
 
-  return measurement === 'px'
+  return unit === 'px'
     ? `${numerator}px`
     : `${(numerator / denominator).toFixed(4)}rem`;
 }
@@ -68,7 +68,7 @@ export function euiFontSizeFromScale(
 export function euiLineHeightFromBaseline(
   scale: _EuiThemeFontScale,
   { base, font }: UseEuiTheme['euiTheme'],
-  { measurement = 'rem', customScale }: _FontScaleOptions = {}
+  { unit = font.defaultUnits, customScale }: _FontScaleOptions = {}
 ) {
   const { baseline, lineHeightMultiplier } = font;
   let numerator = base * font.scale[scale];
@@ -78,7 +78,7 @@ export function euiLineHeightFromBaseline(
   const _lineHeightMultiplier =
     numerator <= base ? lineHeightMultiplier : lineHeightMultiplier * 0.833;
 
-  if (measurement === 'em') {
+  if (unit === 'em') {
     // Even though the line-height via `em` cannot be determined against the pixel baseline grid;
     // we will assume that typically larger scale font-sizes should have a shorter line-height;
     return _lineHeightMultiplier.toFixed(4).toString();
@@ -87,7 +87,7 @@ export function euiLineHeightFromBaseline(
   const pixelValue =
     Math.floor(Math.round(numerator * _lineHeightMultiplier) / baseline) *
     baseline;
-  return measurement === 'px'
+  return unit === 'px'
     ? `${pixelValue}px`
     : `${(pixelValue / denominator).toFixed(4)}rem`;
 }
diff --git a/src/global_styling/variables/typography.ts b/src/global_styling/variables/typography.ts
index f270a7ab6a7..80ebbc8b1cb 100644
--- a/src/global_styling/variables/typography.ts
+++ b/src/global_styling/variables/typography.ts
@@ -12,10 +12,9 @@ import { CSSProperties } from 'react';
  * Font units of measure
  */
 
-export const EuiThemeFontSizeMeasurements = ['rem', 'px', 'em'] as const;
+export const EuiThemeFontUnits = ['rem', 'px', 'em'] as const;
 
-export type _EuiThemeFontSizeMeasurement =
-  (typeof EuiThemeFontSizeMeasurements)[number];
+export type _EuiThemeFontUnit = (typeof EuiThemeFontUnits)[number];
 
 /*
  * Font scale
@@ -59,6 +58,16 @@ export type _EuiThemeFontBase = {
    * https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings
    */
   featureSettings?: string;
+  /**
+   * Sets the default units used for font size & line height set by UI components
+   * like EuiText or EuiTitle. Defaults to `rem`.
+   *
+   * NOTE: This may overridden by some internal usages, e.g.
+   * EuiText's `relative` size which must use `em`.
+   *
+   * @default 'rem'
+   */
+  defaultUnits: _EuiThemeFontUnit;
   /**
    * A computed number that is 1/4 of `base`
    */
diff --git a/src/themes/amsterdam/global_styling/variables/_typography.ts b/src/themes/amsterdam/global_styling/variables/_typography.ts
index f51b71aa0fe..3a95f26a6c5 100644
--- a/src/themes/amsterdam/global_styling/variables/_typography.ts
+++ b/src/themes/amsterdam/global_styling/variables/_typography.ts
@@ -34,6 +34,7 @@ export const fontBase: _EuiThemeFontBase = {
 
   // Careful using ligatures. Code editors like ACE will often error because of width calculations
   featureSettings: "'calt' 1, 'kern' 1, 'liga' 1",
+  defaultUnits: 'rem',
 
   baseline: computed(([base]) => base / 4, ['base']),
   lineHeightMultiplier: 1.5,
diff --git a/upcoming_changelogs/7133.md b/upcoming_changelogs/7133.md
new file mode 100644
index 00000000000..9ec8351cd25
--- /dev/null
+++ b/upcoming_changelogs/7133.md
@@ -0,0 +1,5 @@
+- Added `font.defaultUnits` theme token. EUI component font sizes default to `rem` units - this token allows consumers to configure this to `px` or `em`
+
+**CSS-in-JS conversions**
+
+- Renamed `useEuiFontSize()`'s `measurement` option to `unit` for clarity