UNPKG

@workday/canvas-kit-docs

Version:

Documentation components of Canvas Kit components

424 lines (315 loc) 12.5 kB
import {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight'; import {StorybookStatusIndicator, DownloadLLMFile} from '@workday/canvas-kit-docs'; # Style Props Deprecation Overview ### Purpose As part of the Canvas Kit’s modernization process, we’re moving away from Emotion’s runtime styling and promoting a custom CSS-in-JS solution: `@workday/canvas-kit-styling`. This change improves **performance**, **consistency**, and **maintainability** across our codebase. For more information, view our [Future of](https://github.com/Workday/canvas-kit/discussions/2265) discussion. ### Goals - **Reduce runtime overhead** by removing Emotion’s runtime from `@emotion/react` - **Promote prescriptive, opinionated styling** across Workday - **Enable static CSS compilation** for faster load times and smaller bundles - **Support new design tokens and CSS Variables** for scalable theming - **Ensure proper style merging** and stable selector behavior - **Support advanced styling patterns** like compound styles, modifiers, and `data-parts` > Emotion dynamically injects styles at runtime, causing costly re-renders and cache invalidations. > The new system statically compiles styles at build time for optimal performance. ### Timeline - **Deprecation introduced:** Canvas Kit **v14.1** - **Removal:** _Not immediate_ — style props and `styled()` will continue to function in upcoming releases - **Migration timeline:** Gradual; no immediate codebase-wide update required ## LLM Assisted Migration <StorybookStatusIndicator type="ai" /> We've provided an **LLM migration mapping file** (`llm-style-props-migration.txt`) specifically designed for use with LLM-based code assistants such as [Cursor](https://www.cursor.so/). It contains a compiled LLM consumption version of this v14 Upgrade Guide. It is not intended for direct human reference or team documentation, but rather as structured input for LLMs to automate and assist with your migration process. > **Important:** LLMs can make mistakes. Please verify changes using this Migration Guide. **How to use:** - **View raw file**: Open the file in a new tab to see the complete migration mapping - **Download LLM File**: Save the file locally to upload or paste into your LLM/code assistant - **Use with LLM**: Provide the raw content to your LLM/code assistant as context for automated migration <DownloadLLMFile rawFileLink="https://raw.githubusercontent.com/Workday/canvas-kit/master/modules/docs/llm/llm-style-props-migration.txt" filename="llm-style-props-migration.txt" /> ## Changes Overview ### Replacements Use the new **Canvas Kit Styling** utilities: | Old API | New API | Purpose | | -------------------------------------------------- | -------------------------------- | ------------------------------------------ | | `styled()` | `createStyles` / `createStencil` | Define static or component-level styles | | Inline style props, like `background` or `padding` | `cs` prop | Safely merge class names and styles | | Dynamic values | `createVars` | Manage CSS variables for runtime overrides | | Emotion modifiers | `modifiers`, `compound` | Define consistent appearance variants | ## Canvas Kit Styling <InformationHighlight className="sb-unstyled" cs={{p: {marginBlock: 0}}}> <InformationHighlight.Icon /> <InformationHighlight.Heading>Canvas Kit Styling Docs</InformationHighlight.Heading> For a detailed overview of our styling approach, view our styling docs. <InformationHighlight.Link href="https://workday.github.io/canvas-kit/?path=/docs/styling-getting-started-overview--docs"> Read more </InformationHighlight.Link> </InformationHighlight> Canvas Kit’s styling utilities are built for **static CSS generation**, **token integration**, and **predictable composition**. ### Core APIs - **`createStyles`** — define reusable, static CSS objects. - **`createStencil`** — define reusable, dynamic component styles with parts, vars, and modifiers - **`cs` prop** — apply multiple styles and handle merges consistently to Canvas Kit components ### Best Practices These best practices ensure your components remain **performant**, **consistent**, and **maintainable** under the new Canvas Kit Styling system. #### Define Styles Outside the Render Function Always declare styles at the module level. Creating styles inside the render or component function will trigger component re-render. ✅ **Do** ```tsx // `createStyles` returns a string of className const buttonStyles = createStyles({ backgroundColor: system.color.bg.primary.default, color: system.color.text.inverse, }); export const MyButton = () => <button className={buttonStyles}>Click me</button>; ```**Don’t** ```tsx export const MyButton = () => { const buttonStyles = createStyles({backgroundColor: 'red'}); // bad return <button cs={buttonStyles}>Click me</button>; }; ``` #### Use `createStyles` for Static Styling Use `createStyles` for simple, reusable style objects that do **not** depend on dynamic data or props. ✅ Ideal for: - Defining base styles - Applying static overrides - Styling tokens-based components `createStyles` returns a string of className that can be applied to a React element. If you're applying the class to a Canvas Kit component, you can use the `cs` prop. ```tsx import {BaseButton} from '@workday/canvas-kit-react/button'; import {createStyles} from '@workday/canvas-kit-styling'; // `createStyles` returns a string of className const buttonStyles = createStyles({ backgroundColor: system.color.bg.primary.default, color: system.color.text.inverse, }); export const MyButton = () => <BaseButton cs={buttonStyles}>Click me</button>; ``` #### Use `createStencil` for Dynamic or Complex Styling Use `createStencil` when styles depend on **props**, **variants**, or **component parts**. Examples: - Size or color variants (`primary`, `secondary`) - Compound state combinations (`size=small`, `iconPosition=end`) - Multi-part components (e.g. `Button`, `Card`, `MenuItem`) ✅ **Do** ```tsx const buttonStencil = createStencil({ vars: {color: '', background: ''}, base: ({color, backgroundColor}) => ({ color: cssVar(color, system.color.text.default), backgroundColor: cssVar(backgroundColor, system.color.bg.default), }), modifiers: { variant: { primary: {background: system.color.bg.primary.default}, secondary: {background: system.color.bg.muted.default}, }, }, }); ``` - **vars**: If you initialize the variable with an empty string, it will allow the variable to cascade and be defined. ```tsx const customButtonStencil = createStencil({ base: { // Set the color variable to the primary color [buttonStencil.vars.color]: system.color.fg.primary.default, }, }); ``` - **cssVar**: The `cssVar` function is used when you want to add a default value if the CSS Variable is not defined. - **modifiers**: The `modifiers` property is used to define the styles for the different variants of the component. #### Use `cs` Prop to Merge Styles The `cs` prop merges `className` and `style` attributes safely and consistently. Use this over using style props or className concatenation. ✅ **Do** ```tsx <PrimaryButton cs={[baseStyles, variantStyles]} /> ```**Don’t** ```tsx <PrimaryButton className={`${baseStyles} ${variantStyles}`} /> ``` #### Use Variables for Dynamic Values Instead of inline styles or runtime calculations, use stencil variables. ✅ **Do** ```tsx const primaryButtonStencil = createStencil({ base: { // Use the buttonStencil variable to set the background color [buttonStencil.vars.background]: 'orange', } }) <PrimaryButton cs={primaryButtonStencil} /> ```**Don’t** ```tsx <PrimaryButton cs={{backgroundColor: 'orange'}} /> // breaks static optimization ``` #### Extend Existing Stencils Instead of Overriding Styles When modifying Canvas Kit components, extend the provided `Stencil` instead of creating your own from scratch. ✅ **Do** ```tsx const customIconStencil = createStencil({ extends: systemIconStencil, base: { margin: system.space.x2, }, }); ``` This will inherit both the styles and variables from the `systemIconStencil`. #### Use Modifiers for Variants and States Define component variations (size, color, emphasis) using **modifiers** rather than conditional logic. ✅ **Do** ```tsx const badgeStencil = createStencil({ modifiers: { status: { success: {background: system.color.bg.success.default}, error: {background: system.color.bg.negative.default}, }, }, }); ``` #### Use Compound Modifiers for Complex Conditions When two or more modifiers combine to produce a new style, define a **compound modifier**. ✅ **Do** ```tsx const myCustomStencil = createStencil({ base: { //base styles }, modifiers: { variant: { primary: { // primary variant styles }, }, size: { large: { // large size styles }, }, }, compound: [ { // apply styles when the variant is primary AND the size is large modifiers: {variant: 'primary', size: 'large'}, styles: {paddingInline: system.space.x5}, }, ], }); ``` #### Avoid Nested Stencils Unless Necessary Each Stencil should map to one semantic component. Nested stencils can increase CSS specificity and complexity. Use **parts** instead of deep nesting. ✅ **Do** ```tsx const cardStencil = createStencil({ parts: {header: 'card-header', body: 'card-body'}, base: ({headerPart}) => ({ [headerPart]: { fontWeight: 'bold', }, }), }); <Card cs={cardStencil}> <Card.Heading {...cardStencil.parts.header}>Card Title</Card.Heading> <Card.Body {...cardStencil.parts.body}>Card Body</Card.Body> </Card>; ``` #### Prefer Tokens and System Variables Always use design tokens (`system`) for spacing, colors, typography, etc., instead of raw values. View our System Tokens [docs](https://workday.github.io/canvas-tokens/?path=/docs/docs-system-tokens-overview--docs) for more information. ✅ **Do** ```tsx color: system.color.text.default; margin: system.space.x2; ```**Don’t** ```tsx color: '#333'; margin: '8px'; ``` #### Debugging and Static Compilation - Enable static compilation during development to catch type or value errors early. - Use `as const` for static objects to ensure values are type-locked for the compiler. ✅ **Do** ```tsx const reusableStyles = { position: 'absolute', } as const; ``` #### Don’t Mix Emotion and Static Styling Avoid combining Emotion’s `styled` or `css` with `createStyles` or `createStencil`. It reintroduces runtime style recalculations and negates static benefits. ❌ **Don’t** ```tsx const StyledButton = styled(Button)(styles); <StyledButton cs={createStyles({padding: 8})} />; ``` ## Migration Example ### Style Props #### Before ```typescript import {Flex} from '@workday/canvas-kit-react/layout'; <Flex depth={1} marginX={10} background="frenchVanilla100" />; ``` #### After ```typescript import {Flex} from '@workday/canvas-kit-react/layout'; import {system} from '@workday/canvas-tokens-web'; import {px2rem} from '@workday/canvas-kit-styling'; <Flex cs={{ boxShadow: system.depth[1], marginInline: px2rem(10), background: system.color.bg.default, }} />; ``` - **px2rem**: The `px2rem` function is used to convert a pixel value to a rem value. - Use [CSS logical properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values - Use `system` tokens over `base` tokens for better theming support. ### Emotion styled #### Before (Emotion) ```tsx const StyledButton = styled('button')({ backgroundColor: 'blue', color: 'white', }); ``` #### After (Canvas Kit Styling) ```tsx import {createStyles} from '@workday/canvas-kit-styling'; import {PrimaryButton} from '@workday/canvas-kit-react/button'; import {system} from '@workday/canvas-tokens-web'; const primaryButtonStyles = createStyles({ backgroundColor: system.color.bg.primary.default, color: system.color.text.inverse, }); <PrimaryButton cs={primaryButtonStyles}>Click me</PrimaryButton>; ```