diff --git a/packages/eui/src/components/code/code.styles.ts b/packages/eui/src/components/code/code.styles.ts index b21cdf686ac..dd1b588ec12 100644 --- a/packages/eui/src/components/code/code.styles.ts +++ b/packages/eui/src/components/code/code.styles.ts @@ -10,6 +10,8 @@ import { css } from '@emotion/react'; import { highContrastModeStyles, logicalShorthandCSS, + logicalCSS, + euiLineHeightFromBaseline, } from '../../global_styling'; import { UseEuiTheme } from '../../services'; import { euiCodeSyntaxVariables } from './code_syntax.styles'; @@ -17,6 +19,10 @@ import { euiCodeSyntaxVariables } from './code_syntax.styles'; export const euiCodeStyles = (euiThemeContext: UseEuiTheme) => { const codeSyntaxVariables = euiCodeSyntaxVariables(euiThemeContext); const { euiTheme } = euiThemeContext; + // Get line-height for 's' scale (0.9em relative to parent 'm' scale) + // Since code is 0.9em, we need to calculate line-height based on the effective font size + // Parent is typically 'm' scale, so 0.9em of 'm' is approximately 's' scale + const lineHeight = euiLineHeightFromBaseline('s', euiTheme); return { /* @@ -25,7 +31,9 @@ export const euiCodeStyles = (euiThemeContext: UseEuiTheme) => { euiCode: css` font-family: ${euiTheme.font.familyCode}; font-size: 0.9em; /* 1 */ - ${logicalShorthandCSS('padding', '0.2em 0.5em')} /* 1 */ + line-height: ${lineHeight}; /* Match text line heights */ + ${logicalCSS('height', '20px')} /* Fixed height of 20px */ + ${logicalShorthandCSS('padding', '0 0.5em')} /* 1 - Remove vertical padding to maintain 20px height */ background-color: ${codeSyntaxVariables.inlineBackgroundColor}; ${highContrastModeStyles(euiThemeContext, { forced: ` diff --git a/packages/eui/src/components/text/__snapshots__/text.styles.test.ts.snap b/packages/eui/src/components/text/__snapshots__/text.styles.test.ts.snap index d706004b2d2..ae29bace1a0 100644 --- a/packages/eui/src/components/text/__snapshots__/text.styles.test.ts.snap +++ b/packages/eui/src/components/text/__snapshots__/text.styles.test.ts.snap @@ -3,7 +3,7 @@ exports[`euiTextStyles sizes m 1`] = ` " font-size: 1.1429rem; - line-height: 1.7143rem; + line-height: 1.5714rem; h1 { font-size: 2.1429rem; @@ -15,7 +15,7 @@ exports[`euiTextStyles sizes m 1`] = ` h2 { font-size: 1.7143rem; - line-height: 2.0000rem; + line-height: 2.1429rem; &:not(:first-child) { margin-block-start: 24px; @@ -28,7 +28,7 @@ exports[`euiTextStyles sizes m 1`] = ` h3 { font-size: 1.4286rem; - line-height: 1.7143rem; + line-height: 1.8571rem; &:not(:first-child) { margin-block-start: 24px; @@ -41,7 +41,7 @@ exports[`euiTextStyles sizes m 1`] = ` h4 { font-size: 1.1429rem; - line-height: 1.7143rem; + line-height: 1.5714rem; &:not(:first-child) { margin-block-start: 24px; @@ -67,7 +67,7 @@ exports[`euiTextStyles sizes m 1`] = ` h6 { font-size: 0.8571rem; - line-height: 1.1429rem; + line-height: 1.2857rem; &:not(:first-child) { margin-block-start: 24px; @@ -84,12 +84,12 @@ exports[`euiTextStyles sizes m 1`] = ` pre, > ul, > ol { - margin-block-end: 1.7143rem; + margin-block-end: 1.5714rem; } ul, ol { - margin-inline-start: 1.7143rem; + margin-inline-start: 1.5714rem; } /* The styles of the nested ordered lists follow the style of GitHub @@ -123,7 +123,7 @@ exports[`euiTextStyles sizes m 1`] = ` dt, .eui-definitionListReverse dd { font-size: 1.1429rem; - line-height: 1.7143rem; + line-height: 1.5714rem; } .eui-definitionListReverse dt { @@ -136,7 +136,7 @@ exports[`euiTextStyles sizes m 1`] = ` } pre:not(.euiCodeBlock__pre) { - padding: 1.7143rem; + padding: 1.5714rem; } code:not(.euiCode):not(.euiCodeBlock__code) { @@ -165,11 +165,11 @@ exports[`euiTextStyles sizes m 1`] = ` exports[`euiTextStyles sizes relative 1`] = ` " font-size: 1em; - line-height: 1.5000; + line-height: 1.3750; h1 { font-size: 1.875em; - line-height: 1.2495; + line-height: 1.2000; } h1:not(:last-child) { margin-block-end: 12px; @@ -177,7 +177,7 @@ exports[`euiTextStyles sizes relative 1`] = ` h2 { font-size: 1.5em; - line-height: 1.2495; + line-height: 1.2500; &:not(:first-child) { margin-block-start: 24px; @@ -190,7 +190,7 @@ exports[`euiTextStyles sizes relative 1`] = ` h3 { font-size: 1.25em; - line-height: 1.2495; + line-height: 1.3000; &:not(:first-child) { margin-block-start: 24px; @@ -203,7 +203,7 @@ exports[`euiTextStyles sizes relative 1`] = ` h4 { font-size: 1em; - line-height: 1.5000; + line-height: 1.3750; &:not(:first-child) { margin-block-start: 24px; @@ -216,7 +216,7 @@ exports[`euiTextStyles sizes relative 1`] = ` h5 { font-size: 0.875em; - line-height: 1.5000; + line-height: 1.4286; &:not(:first-child) { margin-block-start: 24px; @@ -246,12 +246,12 @@ exports[`euiTextStyles sizes relative 1`] = ` pre, > ul, > ol { - margin-block-end: 1.5000em; + margin-block-end: 1.3750em; } ul, ol { - margin-inline-start: 1.5000em; + margin-inline-start: 1.3750em; } /* The styles of the nested ordered lists follow the style of GitHub @@ -285,7 +285,7 @@ exports[`euiTextStyles sizes relative 1`] = ` dt, .eui-definitionListReverse dd { font-size: 1em; - line-height: 1.5000; + line-height: 1.3750; } .eui-definitionListReverse dt { @@ -298,7 +298,7 @@ exports[`euiTextStyles sizes relative 1`] = ` } pre:not(.euiCodeBlock__pre) { - padding: 1.5000em; + padding: 1.3750em; } code:not(.euiCode):not(.euiCodeBlock__code) { @@ -316,7 +316,7 @@ exports[`euiTextStyles sizes s 1`] = ` h1 { font-size: 1.8750rem; - line-height: 2.2857rem; + line-height: 2.1429rem; } h1:not(:last-child) { margin-block-end: 8px; @@ -324,7 +324,7 @@ exports[`euiTextStyles sizes s 1`] = ` h2 { font-size: 1.5000rem; - line-height: 1.7143rem; + line-height: 1.8571rem; &:not(:first-child) { margin-block-start: 16px; @@ -337,7 +337,7 @@ exports[`euiTextStyles sizes s 1`] = ` h3 { font-size: 1.2500rem; - line-height: 1.4286rem; + line-height: 1.5714rem; &:not(:first-child) { margin-block-start: 16px; @@ -363,7 +363,7 @@ exports[`euiTextStyles sizes s 1`] = ` h5 { font-size: 0.8750rem; - line-height: 1.1429rem; + line-height: 1.2857rem; &:not(:first-child) { margin-block-start: 16px; @@ -376,7 +376,7 @@ exports[`euiTextStyles sizes s 1`] = ` h6 { font-size: 0.7500rem; - line-height: 1.1429rem; + line-height: 1.2143rem; &:not(:first-child) { margin-block-start: 16px; @@ -459,11 +459,11 @@ exports[`euiTextStyles sizes s 1`] = ` exports[`euiTextStyles sizes xs 1`] = ` " font-size: 0.8571rem; - line-height: 1.1429rem; + line-height: 1.2857rem; h1 { font-size: 1.6071rem; - line-height: 2.0000rem; + line-height: 2.1429rem; } h1:not(:last-child) { margin-block-end: 4px; @@ -471,7 +471,7 @@ exports[`euiTextStyles sizes xs 1`] = ` h2 { font-size: 1.2857rem; - line-height: 1.4286rem; + line-height: 1.5714rem; &:not(:first-child) { margin-block-start: 8px; @@ -497,7 +497,7 @@ exports[`euiTextStyles sizes xs 1`] = ` h4 { font-size: 0.8571rem; - line-height: 1.1429rem; + line-height: 1.2857rem; &:not(:first-child) { margin-block-start: 8px; @@ -510,7 +510,7 @@ exports[`euiTextStyles sizes xs 1`] = ` h5 { font-size: 0.7500rem; - line-height: 1.1429rem; + line-height: 1.2143rem; &:not(:first-child) { margin-block-start: 8px; @@ -523,7 +523,7 @@ exports[`euiTextStyles sizes xs 1`] = ` h6 { font-size: 0.6429rem; - line-height: 0.8571rem; + line-height: 1.0000rem; &:not(:first-child) { margin-block-start: 8px; @@ -540,12 +540,12 @@ exports[`euiTextStyles sizes xs 1`] = ` pre, > ul, > ol { - margin-block-end: 1.1429rem; + margin-block-end: 1.2857rem; } ul, ol { - margin-inline-start: 1.1429rem; + margin-inline-start: 1.2857rem; } /* The styles of the nested ordered lists follow the style of GitHub @@ -579,7 +579,7 @@ exports[`euiTextStyles sizes xs 1`] = ` dt, .eui-definitionListReverse dd { font-size: 0.8571rem; - line-height: 1.1429rem; + line-height: 1.2857rem; } .eui-definitionListReverse dt { @@ -592,7 +592,7 @@ exports[`euiTextStyles sizes xs 1`] = ` } pre:not(.euiCodeBlock__pre) { - padding: 1.1429rem; + padding: 1.2857rem; } code:not(.euiCode):not(.euiCodeBlock__code) { diff --git a/packages/eui/src/components/text/text.styles.ts b/packages/eui/src/components/text/text.styles.ts index a495179b9e3..ee0d241f930 100644 --- a/packages/eui/src/components/text/text.styles.ts +++ b/packages/eui/src/components/text/text.styles.ts @@ -13,6 +13,7 @@ import { logicalShorthandCSS, logicalTextAlignCSS, euiFontSize, + euiLineHeightFromBaseline, _FontScaleOptions, mathWithUnits, } from '../../global_styling'; @@ -202,6 +203,8 @@ const euiScaleText = ( code:not(.euiCode):not(.euiCodeBlock__code) { font-size: .9em; /* 90% of parent font size */ + /* Match text line heights - since code is 0.9em relative to parent 'm' scale, use 's' scale line-height */ + line-height: ${euiLineHeightFromBaseline('s', euiTheme, options)}; } ${highContrastModeStyles(euiThemeContext, { // For EuiCodeBlocks, set the margin on the wrapper instead of on the
diff --git a/packages/eui/src/components/title/__snapshots__/title.styles.test.ts.snap b/packages/eui/src/components/title/__snapshots__/title.styles.test.ts.snap
index ac0381e41c7..c56b09da589 100644
--- a/packages/eui/src/components/title/__snapshots__/title.styles.test.ts.snap
+++ b/packages/eui/src/components/title/__snapshots__/title.styles.test.ts.snap
@@ -5,6 +5,7 @@ exports[`euiTitle mixin returns a static object of title font properties for eac
   "color": "#111C2C",
   "fontSize": "2.1429rem",
   "fontWeight": 600,
+  "letterSpacing": "-0.015rem",
   "lineHeight": "2.5714rem",
 }
 `;
@@ -14,7 +15,8 @@ exports[`euiTitle mixin returns a static object of title font properties for eac
   "color": "#111C2C",
   "fontSize": "1.7143rem",
   "fontWeight": 600,
-  "lineHeight": "2.0000rem",
+  "letterSpacing": "-0.01rem",
+  "lineHeight": "2.1429rem",
 }
 `;
 
@@ -23,7 +25,8 @@ exports[`euiTitle mixin returns a static object of title font properties for eac
   "color": "#111C2C",
   "fontSize": "1.4286rem",
   "fontWeight": 600,
-  "lineHeight": "1.7143rem",
+  "letterSpacing": "-0.005rem",
+  "lineHeight": "1.8571rem",
 }
 `;
 
@@ -32,7 +35,7 @@ exports[`euiTitle mixin returns a static object of title font properties for eac
   "color": "#111C2C",
   "fontSize": "1.1429rem",
   "fontWeight": 600,
-  "lineHeight": "1.7143rem",
+  "lineHeight": "1.5714rem",
 }
 `;
 
@@ -50,6 +53,6 @@ exports[`euiTitle mixin returns a static object of title font properties for eac
   "color": "#111C2C",
   "fontSize": "0.8571rem",
   "fontWeight": 600,
-  "lineHeight": "1.1429rem",
+  "lineHeight": "1.2857rem",
 }
 `;
diff --git a/packages/eui/src/global_styling/functions/__snapshots__/typography.test.tsx.snap b/packages/eui/src/global_styling/functions/__snapshots__/typography.test.tsx.snap
index ce97abf94a8..6b9f83b2af7 100644
--- a/packages/eui/src/global_styling/functions/__snapshots__/typography.test.tsx.snap
+++ b/packages/eui/src/global_styling/functions/__snapshots__/typography.test.tsx.snap
@@ -22,24 +22,24 @@ exports[`euiFontSizeFromScale unit px 1`] = `"16px"`;
 
 exports[`euiFontSizeFromScale unit rem 1`] = `"1.1429rem"`;
 
-exports[`euiLineHeightFromBaseline scale l 1`] = `"1.7143rem"`;
+exports[`euiLineHeightFromBaseline scale l 1`] = `"1.8571rem"`;
 
-exports[`euiLineHeightFromBaseline scale m 1`] = `"1.7143rem"`;
+exports[`euiLineHeightFromBaseline scale m 1`] = `"1.5714rem"`;
 
 exports[`euiLineHeightFromBaseline scale s 1`] = `"1.4286rem"`;
 
-exports[`euiLineHeightFromBaseline scale xl 1`] = `"2.0000rem"`;
+exports[`euiLineHeightFromBaseline scale xl 1`] = `"2.1429rem"`;
 
-exports[`euiLineHeightFromBaseline scale xs 1`] = `"1.1429rem"`;
+exports[`euiLineHeightFromBaseline scale xs 1`] = `"1.2857rem"`;
 
 exports[`euiLineHeightFromBaseline scale xxl 1`] = `"2.5714rem"`;
 
-exports[`euiLineHeightFromBaseline scale xxs 1`] = `"1.1429rem"`;
+exports[`euiLineHeightFromBaseline scale xxs 1`] = `"1.2143rem"`;
 
-exports[`euiLineHeightFromBaseline scale xxxs 1`] = `"0.8571rem"`;
+exports[`euiLineHeightFromBaseline scale xxxs 1`] = `"1.0000rem"`;
 
-exports[`euiLineHeightFromBaseline unit em 1`] = `"1.5000"`;
+exports[`euiLineHeightFromBaseline unit em 1`] = `"1.3750"`;
 
-exports[`euiLineHeightFromBaseline unit px 1`] = `"24px"`;
+exports[`euiLineHeightFromBaseline unit px 1`] = `"22px"`;
 
-exports[`euiLineHeightFromBaseline unit rem 1`] = `"1.7143rem"`;
+exports[`euiLineHeightFromBaseline unit rem 1`] = `"1.5714rem"`;
diff --git a/packages/eui/src/global_styling/functions/typography.test.tsx b/packages/eui/src/global_styling/functions/typography.test.tsx
index 1b86b3bd811..c7cd2b7b37b 100644
--- a/packages/eui/src/global_styling/functions/typography.test.tsx
+++ b/packages/eui/src/global_styling/functions/typography.test.tsx
@@ -70,9 +70,11 @@ describe('euiLineHeightFromBaseline', () => {
 
   describe('custom scale', () => {
     it('allows passing a custom modifier to the existing scale', () => {
+      // xxxs (0.5625) * s (0.875) = 0.4921875 → 16 * 0.4921875 = 7.875px ≈ 8px
+      // Closest match is 9px → 14px line height → 14/14 = 1.0000rem
       expect(
         euiLineHeightFromBaseline('xxxs', euiTheme, { customScale: 's' })
-      ).toEqual('0.8571rem');
+      ).toEqual('1.0000rem');
     });
   });
 
@@ -101,7 +103,7 @@ describe('euiLineHeightFromBaseline', () => {
         wrapper,
       }).result.current;
 
-      expect(euiLineHeightFromBaseline('m', modifiedEuiTheme)).toEqual('24px');
+      expect(euiLineHeightFromBaseline('m', modifiedEuiTheme)).toEqual('22px');
     });
   });
 });
diff --git a/packages/eui/src/global_styling/functions/typography.ts b/packages/eui/src/global_styling/functions/typography.ts
index 1079febb407..21427848728 100644
--- a/packages/eui/src/global_styling/functions/typography.ts
+++ b/packages/eui/src/global_styling/functions/typography.ts
@@ -26,6 +26,71 @@ export interface _FontScaleOptions {
   customScale?: _EuiThemeFontScale;
 }
 
+/**
+ * Fixed mapping of font sizes (in pixels) to line heights (in pixels)
+ * These mappings are consistent across all units (rem, px, em)
+ */
+const FONT_SIZE_TO_LINE_HEIGHT_MAP: Record = {
+  9: 14,   // xxxs
+  11: 17,  // xxs
+  12: 18,  // xs
+  14: 20,  // s
+  16: 22,  // m
+  20: 26,  // l
+  24: 30,  // xl
+  30: 36,  // xxl
+};
+
+/**
+ * Gets the line height in pixels for a given font size in pixels
+ * Uses the fixed mapping, or calculates proportionally for intermediate values
+ */
+function getLineHeightForFontSize(fontSizePx: number): number {
+  // Exact match
+  if (FONT_SIZE_TO_LINE_HEIGHT_MAP[fontSizePx]) {
+    return FONT_SIZE_TO_LINE_HEIGHT_MAP[fontSizePx];
+  }
+  
+  // For intermediate values, find the closest match and interpolate
+  const sizes = Object.keys(FONT_SIZE_TO_LINE_HEIGHT_MAP)
+    .map(Number)
+    .sort((a, b) => a - b);
+  
+  // Find the closest size
+  let closestSize = sizes[0];
+  let minDiff = Math.abs(fontSizePx - closestSize);
+  
+  for (const size of sizes) {
+    const diff = Math.abs(fontSizePx - size);
+    if (diff < minDiff) {
+      minDiff = diff;
+      closestSize = size;
+    }
+  }
+  
+  // Use the line height from the closest match
+  return FONT_SIZE_TO_LINE_HEIGHT_MAP[closestSize];
+}
+
+/**
+ * Returns letter-spacing for specific font scales
+ * @param scale - The font scale key
+ * @param theme - Requires the `base` and `font` keys
+ * @returns string | undefined - Letter-spacing value in rem, or undefined for scales without letter-spacing
+ */
+export function euiLetterSpacingFromScale(
+  scale: _EuiThemeFontScale,
+  { base, font }: UseEuiTheme['euiTheme']
+): string | undefined {
+  const letterSpacingMap: Record = {
+    l: '-0.005rem',
+    xl: '-0.01rem',
+    xxl: '-0.015rem',
+  };
+  
+  return letterSpacingMap[scale];
+}
+
 /**
  * Calculates the font-size value based on the provided scale key
  * @param scale - The font scale key
@@ -54,15 +119,13 @@ export function euiFontSizeFromScale(
 }
 
 /**
- * Calculates the line-height to the closest multiple of the baseline
- * EX: A proper line-height for text is 1.5 times the font-size.
- *     If our base font size (euiFontSize) is 16, and our baseline is 4. To ensure the
- *     text stays on the baseline, we pass a multiplier to calculate a line-height.
+ * Returns the line-height based on a fixed mapping of font sizes to line heights
+ * The mapping ensures consistent line heights regardless of unit (rem, px, em)
  * @param scale - The font scale key
  * @param theme - Requires the `base` and `font` keys
  * @param options - Optional parameters - see _FontScaleOptions
  *
- * @returns string - Calculated line-height value aligned to baseline
+ * @returns string - Line-height value from the fixed mapping
  */
 
 export function euiLineHeightFromBaseline(
@@ -70,26 +133,30 @@ export function euiLineHeightFromBaseline(
   { base, font }: UseEuiTheme['euiTheme'],
   { unit = font.defaultUnits, customScale }: _FontScaleOptions = {}
 ) {
-  const { baseline, lineHeightMultiplier } = font;
-  let numerator = base * font.scale[scale];
-  if (customScale) numerator *= font.scale[customScale];
-  const denominator = base * font.scale[font.body.scale];
-
-  const _lineHeightMultiplier =
-    numerator <= base ? lineHeightMultiplier : lineHeightMultiplier * 0.833;
-
+  // Calculate the font size in pixels
+  let fontSizePx = base * font.scale[scale];
+  if (customScale) fontSizePx *= font.scale[customScale];
+  
+  // Round to nearest integer for pixel matching
+  const fontSizePxRounded = Math.round(fontSizePx);
+  
+  // Get the corresponding line height in pixels
+  const lineHeightPx = getLineHeightForFontSize(fontSizePxRounded);
+  
+  // Convert to the requested unit
+  if (unit === 'px') {
+    return `${lineHeightPx}px`;
+  }
+  
   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();
+    // For em, return the ratio of line-height to actual font-size (not rounded)
+    const ratio = lineHeightPx / fontSizePx;
+    return ratio.toFixed(4).toString();
   }
-
-  const pixelValue =
-    Math.floor(Math.round(numerator * _lineHeightMultiplier) / baseline) *
-    baseline;
-  return unit === 'px'
-    ? `${pixelValue}px`
-    : `${(pixelValue / denominator).toFixed(4)}rem`;
+  
+  // For rem, convert relative to the body font size
+  const denominator = base * font.scale[font.body.scale];
+  return `${(lineHeightPx / denominator).toFixed(4)}rem`;
 }
 
 /**
diff --git a/packages/eui/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap b/packages/eui/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap
index d2ee7c44058..14d1aa01b85 100644
--- a/packages/eui/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap
+++ b/packages/eui/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap
@@ -3,6 +3,7 @@
 exports[`euiFontSize handles the optional customScale property by multiplying it against the passed scale: l scale with xxs customScale 1`] = `
 {
   "fontSize": "0.9821rem",
+  "letterSpacing": "-0.005rem",
   "lineHeight": "1.4286rem",
 }
 `;
@@ -10,42 +11,44 @@ exports[`euiFontSize handles the optional customScale property by multiplying it
 exports[`euiFontSize handles the optional customScale property by multiplying it against the passed scale: m scale with xs customScale 1`] = `
 {
   "fontSize": "0.8571rem",
-  "lineHeight": "1.1429rem",
+  "lineHeight": "1.2857rem",
 }
 `;
 
 exports[`euiFontSize handles the optional customScale property by multiplying it against the passed scale: s scale with xl customScale 1`] = `
 {
   "fontSize": "1.5000rem",
-  "lineHeight": "1.7143rem",
+  "lineHeight": "1.8571rem",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em l 1`] = `
 {
   "fontSize": "1.25em",
-  "lineHeight": "1.2495",
+  "letterSpacing": "-0.005rem",
+  "lineHeight": "1.3000",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em m 1`] = `
 {
   "fontSize": "1em",
-  "lineHeight": "1.5000",
+  "lineHeight": "1.3750",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em s 1`] = `
 {
   "fontSize": "0.875em",
-  "lineHeight": "1.5000",
+  "lineHeight": "1.4286",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em xl 1`] = `
 {
   "fontSize": "1.5em",
-  "lineHeight": "1.2495",
+  "letterSpacing": "-0.01rem",
+  "lineHeight": "1.2500",
 }
 `;
 
@@ -59,35 +62,37 @@ exports[`euiFontSize returns an object of font-size and line-height for each sca
 exports[`euiFontSize returns an object of font-size and line-height for each scale em xxl 1`] = `
 {
   "fontSize": "1.875em",
-  "lineHeight": "1.2495",
+  "letterSpacing": "-0.015rem",
+  "lineHeight": "1.2000",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em xxs 1`] = `
 {
   "fontSize": "0.6875em",
-  "lineHeight": "1.5000",
+  "lineHeight": "1.5455",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale em xxxs 1`] = `
 {
   "fontSize": "0.5625em",
-  "lineHeight": "1.5000",
+  "lineHeight": "1.5556",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale px l 1`] = `
 {
   "fontSize": "20px",
-  "lineHeight": "24px",
+  "letterSpacing": "-0.005rem",
+  "lineHeight": "26px",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale px m 1`] = `
 {
   "fontSize": "16px",
-  "lineHeight": "24px",
+  "lineHeight": "22px",
 }
 `;
 
@@ -101,20 +106,22 @@ exports[`euiFontSize returns an object of font-size and line-height for each sca
 exports[`euiFontSize returns an object of font-size and line-height for each scale px xl 1`] = `
 {
   "fontSize": "24px",
-  "lineHeight": "28px",
+  "letterSpacing": "-0.01rem",
+  "lineHeight": "30px",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale px xs 1`] = `
 {
   "fontSize": "12px",
-  "lineHeight": "16px",
+  "lineHeight": "18px",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale px xxl 1`] = `
 {
   "fontSize": "30px",
+  "letterSpacing": "-0.015rem",
   "lineHeight": "36px",
 }
 `;
@@ -122,28 +129,29 @@ exports[`euiFontSize returns an object of font-size and line-height for each sca
 exports[`euiFontSize returns an object of font-size and line-height for each scale px xxs 1`] = `
 {
   "fontSize": "11px",
-  "lineHeight": "16px",
+  "lineHeight": "17px",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale px xxxs 1`] = `
 {
   "fontSize": "9px",
-  "lineHeight": "12px",
+  "lineHeight": "14px",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem l 1`] = `
 {
   "fontSize": "1.4286rem",
-  "lineHeight": "1.7143rem",
+  "letterSpacing": "-0.005rem",
+  "lineHeight": "1.8571rem",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem m 1`] = `
 {
   "fontSize": "1.1429rem",
-  "lineHeight": "1.7143rem",
+  "lineHeight": "1.5714rem",
 }
 `;
 
@@ -157,20 +165,22 @@ exports[`euiFontSize returns an object of font-size and line-height for each sca
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem xl 1`] = `
 {
   "fontSize": "1.7143rem",
-  "lineHeight": "2.0000rem",
+  "letterSpacing": "-0.01rem",
+  "lineHeight": "2.1429rem",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem xs 1`] = `
 {
   "fontSize": "0.8571rem",
-  "lineHeight": "1.1429rem",
+  "lineHeight": "1.2857rem",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem xxl 1`] = `
 {
   "fontSize": "2.1429rem",
+  "letterSpacing": "-0.015rem",
   "lineHeight": "2.5714rem",
 }
 `;
@@ -178,14 +188,14 @@ exports[`euiFontSize returns an object of font-size and line-height for each sca
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem xxs 1`] = `
 {
   "fontSize": "0.7857rem",
-  "lineHeight": "1.1429rem",
+  "lineHeight": "1.2143rem",
 }
 `;
 
 exports[`euiFontSize returns an object of font-size and line-height for each scale rem xxxs 1`] = `
 {
   "fontSize": "0.6429rem",
-  "lineHeight": "0.8571rem",
+  "lineHeight": "1.0000rem",
 }
 `;
 
diff --git a/packages/eui/src/global_styling/mixins/_typography.ts b/packages/eui/src/global_styling/mixins/_typography.ts
index dbaa7b06f65..d0f3f29cf8d 100644
--- a/packages/eui/src/global_styling/mixins/_typography.ts
+++ b/packages/eui/src/global_styling/mixins/_typography.ts
@@ -11,6 +11,7 @@ import { css } from '@emotion/react';
 import {
   euiLineHeightFromBaseline,
   euiFontSizeFromScale,
+  euiLetterSpacingFromScale,
   _FontScaleOptions,
 } from '../functions/typography';
 import {
@@ -27,19 +28,22 @@ import { logicalCSS } from '../functions';
 export type EuiThemeFontSize = {
   fontSize: CSSProperties['fontSize'];
   lineHeight: CSSProperties['lineHeight'];
+  letterSpacing?: CSSProperties['letterSpacing'];
 };
 
 /**
- * Returns font-size and line-height
+ * Returns font-size, line-height, and letter-spacing (for larger scales)
  */
 export const euiFontSize = (
   { euiTheme }: UseEuiTheme,
   scale: _EuiThemeFontScale,
   options?: _FontScaleOptions
 ): EuiThemeFontSize => {
+  const letterSpacing = euiLetterSpacingFromScale(scale, euiTheme);
   return {
     fontSize: euiFontSizeFromScale(scale, euiTheme, options),
     lineHeight: euiLineHeightFromBaseline(scale, euiTheme, options),
+    ...(letterSpacing && { letterSpacing }),
   };
 };
 export const useEuiFontSize = (
diff --git a/packages/website/docs/getting-started/theming/tokens/typography/font-scale-hook.mdx b/packages/website/docs/getting-started/theming/tokens/typography/font-scale-hook.mdx
index 780c429577f..b98f5999643 100644
--- a/packages/website/docs/getting-started/theming/tokens/typography/font-scale-hook.mdx
+++ b/packages/website/docs/getting-started/theming/tokens/typography/font-scale-hook.mdx
@@ -9,6 +9,8 @@ import { EuiSpacer } from '@elastic/eui';
 
 The typographic scale is loosely based on the Major Third (1.250) typographic scale.
 
+Font sizes are paired with fixed line-height values to ensure consistent typography across all units. Each font size has a corresponding line-height that remains consistent whether using `rem`, `px`, or `em` units.
+
 While these functions and hooks exist to get precise font sizing and associated line-height, we still highly recommend using the [EuiText](../../../../components/display/text.mdx) and [EuiTitle](../../../../components/display/title.mdx) components as wrappers of your content instead.
 
 import { FontSizePreview } from './preview_font_scale';
diff --git a/packages/website/docs/getting-started/theming/tokens/typography/preview_font_scale.tsx b/packages/website/docs/getting-started/theming/tokens/typography/preview_font_scale.tsx
index 839ae60f387..9f51503ef89 100644
--- a/packages/website/docs/getting-started/theming/tokens/typography/preview_font_scale.tsx
+++ b/packages/website/docs/getting-started/theming/tokens/typography/preview_font_scale.tsx
@@ -76,7 +76,7 @@ export const FontScaleTable = () => {
             legend="Value unit to show in table"
             options={unitButtons}
             idSelected={unitSelected}
-            onChange={(id) => setUnitSelected(id as _EuiThemeFontUnit)}
+            onChange={(id) => setUnitSelected(id as typeof EuiThemeFontUnits[number])}
             color="accent"
             isFullWidth
           />