Migrating from Sass to Emotion
This page is meant as a handy reference/cheatsheet on how to migrate specific Sass variables and mixins to their Emotion counterparts.
Variables
Sizes
For a full list of tokens, see
Sizing tokens.Sass | Emotion |
---|---|
$euiSize | useEuiTheme().euiTheme.size.base |
$euiSizeM | useEuiTheme().euiTheme.size.m |
$euiSizeXS /XL /etc | All of these sizes convert to lowercase equivalents, euiTheme.size.xs /.xl etc |
N/A | Note that there are 3 new sizes in our CSS-in-JS tokens to take advantage of, that may help simplify Sass math/calcs: xxs (2px), xxxl (48px) , and xxxxl (64px) |
Performing math on size tokens
It's worth highlighting that these size tokens return CSS strings and not numbers. This means something like $euiSize * 10
requires much more syntactical sugar than it previously did in Sass. If you need to calculate a custom size, you can use one of these 3 methods:
euiTheme.base
returns a number (16 by default) that can have math performed on it, e.g:tsx code block:const width = `${useEuiTheme().euiTheme.base * 10}px`; // '160px'
- EUI offers a
mathWithUnits
utility that preserves the unit of the passed string. Example usage:tsx code block:import { mathWithUnits } from '@elastic/eui'; const SomeComponent = () => { const { euiTheme } = useEuiTheme(); const width = mathWithUnits(euiTheme.size.base, (x) => x * 10); // Returns '160px' // The util also accepts multiple tokens, e.g. const height = mathWithUnits([euiTheme.size.xl, euiTheme.size.xs], (x, y) => x + y); // Returns '44px' }
- You can also prefer to use CSS's built-in
calc()
function, e.g.text code block:css` width: calc(${euiTheme.size.base} * 10); `
Colors
For a full list of tokens, see Color tokens.
Sass | Emotion |
---|---|
$euiColorPrimary /$euiColorSuccessText /etc | useEuiTheme().euiTheme.colors.primary / useEuiTheme().euiTheme.colors.successText (same lowercase naming scheme for all brand colors) |
$euiColorMediumShade /EmpyShade /etc |
|
$euiPageBackgroundColor | useEuiTheme().euiTheme.colors.body |
$euiTextColor | useEuiTheme().euiTheme.colors.text |
$euiTitleColor | useEuiTheme().euiTheme.colors.title |
$euiTextSubduedColor | useEuiTheme().euiTheme.colors.subduedText |
$euiColorDisabled /$euiColorDisabledText | useEuiTheme().euiTheme.colors.disabled /.disabledText |
$euiColorHighlight | useEuiTheme().euiTheme.colors.highlight |
$euiColorGhost | useEuiTheme().euiTheme.colors.ghost (consider replacing this with fullShade/emptyShade instead) |
$euiColorInk |
|
Color palettes
$euiColorPaletteBlind
is now a function that generates a customizable array of palettes. To use it as-is from its previous Sass incarnation, simple invoke it with no arguments passed:
tsx code block:import { euiColorPaletteBlind, euiPaletteColorBlindBehindText } from '@elastic/eui'; // Note that these utils can be called statically / outside of hooks or react components const visColors = euiColorPaletteBlind(); const visBackgroundColors = euiPaletteColorBlindBehindText(); const SomeComponent = () => <div css={{ color: visColors[0], backgroundColor: visBackgroundColors[1] }} />
For a full list of arguments, see Color palettes.
Sass | CSS-in-JS |
---|---|
$euiColorVis0 | euiColorPaletteBlind()[0] |
$euiColorVis1_behindText | euiPaletteColorBlindBehindText()[1] |
... | And so forth for all numbers. |
Typography
For a full list of tokens, see Typography tokens.
Sass | CSS-in-JS |
---|---|
$euiFontWeightBold | useEuiTheme().euiTheme.font.weight.bold (same naming scheme for all weights) |
$euiFontFamily | useEuiTheme().euiTheme.font.family |
$euiCodeFontFamily | useEuiTheme().euiTheme.font.familyCode |
$euiFontFeatureSettings | useEuiTheme().euiTheme.font.featureSettings |
$euiLineHeight | useEuiTheme().euiTheme.font.lineHeightMultiplier |
$euiTextScale | useEuiTheme().euiTheme.font.scale |
Unfortunately, font sizes are no longer static tokens, and must be calculated using a function/hook instead. See the below "Typography" mixin section.
Z-index levels
Sass | CSS-in-JS |
---|---|
$euiZLevel0 | useEuiTheme().euiTheme.levels.content |
$euiZLevel1 | This can be either levels.header , levels.flyout , or levels.maskBelowHeader , depending on the context/use case. |
$euiZLevel2 | useEuiTheme().euiTheme.levels.menu |
$euiZLevel6 | This can be either levels.mask or levels.navigation , depending on the context |
$euiZLevel8 | useEuiTheme().euiTheme.levels.modal |
$euiZLevel9 | useEuiTheme().euiTheme.levels.toast |
$euiZLevel3 , $euiZLevel4 , $euiZLevel5 , $euiZLevel7 | With our Emotion conversion, we've deprecated the use of generic numbered levels, so these levels no longer exist. We recommend adjusting to the nearest semantic meaning, or if necessary, using a static number (if no meaning is associated with EUI components). |
A quick note about math with z-index levels - while they're typed in our theme as potentially being either a string or number (the default type for CSS properties), the returned tokens are numbers and can have math performed on them as-is (e.g. addition).
Borders
For a full list of tokens, see Border tokens.
Sass | CSS-in-JS |
---|---|
$euiBorderRadius | useEuiTheme().euiTheme.border.radius.medium |
$euiBorderRadiusSmall | useEuiTheme().euiTheme.border.radius.small |
$euiBorderWidthThin | useEuiTheme().euiTheme.border.width.thin |
$euiBorderWidthThick | useEuiTheme().euiTheme.border.width.thick |
$euiBorderColor | useEuiTheme().euiTheme.border.color |
$euiBorderThin | useEuiTheme().euiTheme.border.thin |
$euiBorderThick | useEuiTheme().euiTheme.border.thick |
$euiBorderEditable | useEuiTheme().euiTheme.border.editable |
Animations
Sass | CSS-in-JS |
---|---|
$euiAnimSlightBounce | useEuiTheme().euiTheme.animation.bounce |
$euiAnimSlightResistance | useEuiTheme().euiTheme.animation.resistance |
$euiAnimSpeedExtraFast | useEuiTheme().euiTheme.animation.extraFast |
$euiAnimSpeedFast | useEuiTheme().euiTheme.animation.fast |
$euiAnimSpeedNormal | useEuiTheme().euiTheme.animation.normal |
$euiAnimSpeedSlow | useEuiTheme().euiTheme.animation.slow |
$euiAnimSpeedExtraSlow | useEuiTheme().euiTheme.animation.extraSlow |
Form variables โ ๏ธ
EUI currently does not have a migration path for $euiForm
Sass variables. Until we have one, we will not be deprecating these variables.
Mixins
Typography
As mentioned above, $euiFontSize*
tokens no longer exist. Instead, we require using a utility that returns both a fontSize
and lineHeight
in object format. In general, if possible, we strongly recommend using EuiText and EuiTitle instead of directly applying font sizes via CSS.
If you absolutely cannot use a component, we generally recommend the useEuiFontSize()
hook to replace font styling:
tsx code block:import { useEuiFontSize } from '@elastic/eui'; import { css } from '@emotion/react'; const SomeComponent = () => { const cssStyles = [ useEuiFontSize('l'), css`color: red;` ]; return <div css={cssStyles} /> }
tsx code block:import { useEuiFontSize } from '@elastic/eui'; import { css } from '@emotion/react'; const SomeComponent = () => { const euiThemeContext = useEuiTheme(); const cssStyles = css` font-size: ${useEuiFontSize('l').fontSize}; line-height: 1; `; return <div css={cssStyles} /> };
Sass | CSS-in-JS |
---|---|
@include euiFontSizeS /L /etc | useEuiFontSize('xxxs' through 'xxl') |
@include euiFont | Deprecated. Use font-family: ${euiTheme.font.family}; or font-weight: ${euiTheme.font.weight.regular}; if necessary instead |
@include euiCodeFont | Deprecated. Use font-family: ${euiTheme.font.familyCode}; instead |
@include euiText | Deprecated. Use <EuiText /> or if necessary, color: ${euiTheme.colors.text} instead |
@include euiTitle | Deprecated. Use <EuiTitle /> instead (strongly recommended)If absolutely necessary, you may reach into the EuiTitle component via import { euiTitle } from '@elastic/eui/lib/components/title/title.styles'; , but this is generally not recommended as Kibana has issues typing @elastic/eui/lib |
@include euiTextTruncate and @include euiTextBreakWord | Consider simply applying .eui-textTruncate or .eui-textBreakWord as a vanilla className (simplest option). Or, import { euiTextBreakWord, euiTextTruncate } from '@elastic/eui'; and use it as css={euiTextTruncate()} |
See Typography utilities for a full list of className
utilities and documentation.
Responsive
EUI's breakpoint utilities have been generally enhanced to exceed their Sass capabilities. With that in mind, we recommend a more nuanced approach to migrating media queries:
Sass | CSS-in-JS |
---|---|
@include euiBreakpoint('s', 'm') | useEuiBreakpoint(['s', 'm']) |
Media queries ending with @include euiBreakpoint(..., 'xl') e.g., @include euiBreakpoint('m,' 'l', 'xl') | useEuiMinBreakpoint('m') We recommend preferring a single min/max breakpoint, as this helps account for themes with custom breakpoints |
Media queries beginning with @include euiBreakpoint('xs', ...) e.g., @include euiBreakpoint('xs', 's') | useEuiMaxBreakpoint('m') See above. If converted from @euiBreakpoint , should be a size higher than the ending size |
Example usage:
tsx code block:import { useEuiMinBreakpoint, useEuiMaxBreakpoint, useEuiBreakpoint } from '@elastic/eui'; const SomeComponent = () => { const cssStyles = css` ${useEuiMaxBreakpoint('m')} { color: red; /* Text will be red under the 'm' breakpoint */ } ${useEuiBreakpoint(['m', 'l'])} { color: yellow; /* Text will be yellow between the 'm and 'xl' breakpoints */ } ${useEuiMinBreakpoint('xl')} { color: green; /* Text will be green above the 'xl' breakpoint */ } ` return <div css={cssStyles />; }
For a list of all default breakpoints and visual demonstration of these utilities, see Breakpoint utilities.
Shadows
Sass | CSS-in-JS |
---|---|
@include euiSlightShadow | useEuiShadow('xs') |
@include euiBottomShadowSmall | useEuiShadow('s') |
@include euiBottomShadowMedium | useEuiShadow('m') |
@include euiBottomShadow | useEuiShadow('l') |
@include euiBottomShadowLarge | useEuiShadow('xl') |
@include euiBottomShadowFlat | useEuiShadowFlat() |
@include euiSlightShadowHover | useEuiSlightShadowHover() |
Scrolling
For a visual demonstration of these mixins, see Scroll utilities.
Sass | CSS-in-JS |
---|---|
@include euiScrollBar | useEuiScrollBar() , or apply the .eui-scrollBar className |
@include euiYScroll | useEuiOverflowScroll('y') , or apply the .eui-yScroll className |
@include euiYScrollWithShadows | useEuiOverflowScroll('y', true) |
@include euiXScroll | useEuiOverflowScroll('x') , or apply the .eui-xScroll className |
@include euiXScrollWithShadows | useEuiOverflowScroll('x', true) |
Non-hook utilities
If using a hook is onerous to migrate within the existing code for any reason (e.g. conditional returns, nested hooks, etc.), you may use non-hook versions of each utility. For example, you can import euiFontSize
instead of useEuiFontSize
, euiBreakpoint
instead of useEuiBreakpoint
, euiShadow
instead of useEuiShadow
, and so on and so forth.
tsx code block:import { euiFontSize, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; const SomeComponent = ({ isLoading, hasButton }) => { const euiThemeContext = useEuiTheme(); // Conditional return before css`` is used if (isLoading) return <LoadingComponent />; // Nested hook usage const someButton = useMemo(() => { if (!hasButton) return null; const cssStyles = css` ${euiFontSize(euiThemeContext, 'l')} color: red; `; return <button css={cssStyles}>Conditional button</button>; }, [hasButton, euiThemeContext]); return <>{someButton}{children}</> };
Alternatively, you can also take advantage of Emotion's theme context API to obtain the current EUI theme without useEuiTheme()
as a nice syntactical sugar shortcut. See also: Consuming with Emotion's theming
tsx code block:import { euiFontSize } from '@elastic/eui'; import { css } from '@emotion/react'; const SomeComponent = ({ isLoading }) => { if (isLoading) return null; return ( <div css={(euiThemeContext) => css` ${euiFontSize(euiThemeContext, 'l')} color: red; ` /> ); }
Please note, that if you encounter type errors with the theme parameter inside of the css
function, you'll need to make your Plugin is set up to use Kibana's emotion.d.ts file.
To do this, add in the aforementioned emotion.d.ts
with it's path relative to location of the typings
directory as the value of the include
property for the tsconfig.json
file that exists within your plugin.