# Lightning Component Styling RFC > Author: Claudio Brandolini ## Summary This RFC introduces a novel approach to our dedicated styles. It leans on our existing approach to having a `design` folder, but is intended to make our component styling implementation simpler than it is now. ## Description The new proposed approach steps away from some of the challenges present with the existing approach. #### Current challenges: - There's currently a lot of non-DRY-ness - i.e. a lot of repeated variables. - The current design file can be unmaintainable long term, partly due to manually having to maintain a separate interface, and partly due to having variable names sometimes only tangentially related to the style parameter being used. Here's a real-world example of the RFC can be found here: [Component](https://github.com/HBOCodeLabs/Codex/blob/0869809a062f268e78f9f246b0ed06dfcf9bd196/apps/hbomax-lightning/src/packlets/video-player/components/chrome-redesign/components/PlayPauseFeedback.tsx#L62-L71) & [Style](https://github.com/HBOCodeLabs/Codex/blob/0869809a062f268e78f9f246b0ed06dfcf9bd196/apps/hbomax-lightning/src/packlets/video-player/components/chrome-redesign/design/PlayPauseFeedback.styles.ts). To compare, here's our existing structure has the following setup: [Component](https://github.com/HBOCodeLabs/Codex/blob/d29f05e336f3f0c169d63d61c55a8a8f385c67a0/apps/hbomax-lightning/src/packlets/content/components/content-details/ContentDetails.tsx#L125-L183) & [Style](https://github.com/HBOCodeLabs/Codex/blob/d29f05e336f3f0c169d63d61c55a8a8f385c67a0/apps/hbomax-lightning/src/packlets/content/design/layout/content-detail.ts). ## Motivation - This will be relatively easy to migrate to if a developer already knows CSS-in-JS. - This should be easier to use to style components in comparison to our existing setup. - We'll be able to move the majority of a component's styling outside the template, retaining just the core elements such as `bindProp`, etc. ## Code examples ### Components Components are styled through files named following the `ComponentName.styles.ts` format. The files will export an object of this format: ```typescript export interface IElementStyles { style?: IStyleProps; variants?: { [key: string]: IStyleProps }; elements?: { [key: string]: IElementStyles }; } ``` The outermost `style` will contain styles for the container component, and `variants` some additional styles which will only be present under certain conditions (on/off states etc). `elements` be a key-value structure repeating the same format for each child element, thus making the styles format isomorphic to the component's markup and familiar to anyone who used `sass` or `styled-components`. What follows is an example of an icon button with a hover state and two variants, for a play and pause icon. `PlayPauseButton.style.ts` ```typescript const containerSize: number = 100; const halfSize: number = containerSize / 2; export const PlayPauseButton = getStyles({ style: { w: containerSize, h: containerSize color: resolveColor('iconButtonBG'), texture: lng.Tools.getRoundRect(containerSize, containerSize, halfSize), }, variants: { default: { color: resolveColor('iconButtonBGdefault'), }, selected: { color: resolveColor('iconButtonBGselected'), } }, elements: { icon: { style: { x: halfSize, y: halfSize, mountX: 0.5, color: resolveColor('iconButton') }, variants: { playing: { texture: lng.Tools.getSvgTexture(playIcon, halfSize, halfSize) }, paused: { texture: lng.Tools.getSvgTexture(pauseIcon, halfSize, halfSize) } } } } }); ``` ```typescript import { PlayPauseButton as Design } from './PlayPauseButton.styles.ts'; class PlayPauseButton extends lng.Component { // (...) public _template(): { const { style, variants, elements } = Design; return ( <component id={Tags.PlayPauseButton} {...style} {...this.$selected ? variants.selected : variants.default} > <element id={Tags.PlayPauseIcon} {...elements.icon.style} {...elements.icon.variant[this.$playing ? 'playing' : 'paused'} /> </component> ) } } ``` ### Layout Used for pages or full-page components; the properties are limited to the page's children containers and their size / position. This way, we can quickly have an overview of how elements are laid out in the page, and the children will not have to care about the absolute vs relative positions (ie, [0, 0] will always be the top left corner of each child component. Here is an example layout with header, footer and two columns. `Homepage.layout.ts` ```typescript interface IHomepageLayout { Header: ILayoutProps; Footer: ILayoutProps; Main: ILayoutProps; }; const headerHeight:number = 200; export const HomepageLayout: IHomepageLayout = { Header: { w: deviceScreenSize.width, h: headerHeight, y: 0, x: 0 }, Main: { w: deviceScreenSize.width, h: deviceScreenSize - headerHeight * 2, y: HeaderHeight, x: 0 }, Footer: { w: deviceScreenSize.width, h: headerHeight, y: deviceScreenSize - headerHeight, x: 0, } }; ``` `Homepage.ts` ```typescript import { HomepageLayout } from './Homepage.layout.ts'; class Homepage extends lgn.component { private _template() { const { Header, Main, Footer } = HomepageLayout; return ( <component> <component id='Header' {...Header}> {/* header content */} </component> <component id='Main' {...Main}> {/* main content */} </component> <component id='Footer' {...Footer}> {/* footer content */} </component> </component> ) } } ```