# 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>
)
}
}
```