# Declarative layout

## Why?

One of the main reasons we are building Green Core using web components is style encapsulation. The use
of Shadow DOM greatly reduces the risk of styling conflicts in a micro-frontend architecture environment.

This is great for styling the components themselves, but what about the rest of the stuff in an application?
Things like margins, paddings, and grid systems also need styling. These sorts of things are usually handled
by utility classes in traditional CSS frameworks. Utility classes are good, because you don't need to think
about class names for everything. It allows you to quickly build out a responsive layout without writing
a lot of CSS, and it also makes it clear from looking at the markup what the layout is supposed to be.

The main problem with utility classes, in our case, is that they are, in fact, still CSS classes. And CSS classes
can, and will, lead to conflicts.

But, you may ask, if everyone just agrees to use Tailwind or Bootstrap, or some other available
library, won't that solve the problem? Well, it may, initially. But as is always the case with libraries,
they evolve over time. They have to, because CSS evolves over time. And so it inevitably leads to a version
lock-in effect. Because if the next version of Bootstrap have any breaking changes, it means that every
micro-frontend needs to upgrade at the same time to avoid conflicts. This is not a good situation to be in,
because coordinating upgrades across multiple teams and products is hard, bordering on impossible.

And even if we could solve the lock-in problem, there is still the issue of the size of the CSS payload. Any utility
framework will have a lot of utility classes, and if you only use a few of them, you may be shipping a lot of
unused CSS to the client. In a single application context, this is typically not that big of an issue, because there
are ways to tree-shake the classes and keep only the used ones. This (amongst other things) is what the Tailwind
compiler does for you. But in a micro-frontend environment, it is often not possible to determine ahead of time which
classes are going to be used in a given document, since it may consist of multiple independently developed parts.

The declarative layout system in Green Core is an attempt to solve these problems in a way that let's us have the
cake and eat it too.

## How?

Instead of utility classes, the declarative layout system generates CSS on the fly and injects into the
shadow roots of components. It does this using something we call `style expression properties`. These properties
are used to inform the component what CSS it needs to generate and inject into its Shadow DOM.

The system introduces a set of layout oriented components:

- `<gds-div>`
  - `<gds-grid>`
  - `<gds-flex>`
  - `<gds-card>`
  - `<gds-text>`

The hierechy in the list here is intentional. `<gds-div>` is the base component, providing all the base properties,
while the other ones extend this base with specific defaults, and in some cases, additional properties.

Additionally, some style expression properties are available on other components, where it makes sense. For example,
`<gds-button>` supports horizontal sizing properties, margin properties and flex/grid child items properties. Check
the API table for each component to see which properties are available. They are listed under a separate section in
the API table.

### Responsiveness

Style expression properties allows you to write responsive styles in a compact and declarative way. Here is an example:

```html
<!-- Here, we're setting the default padding to `xs`, but increasing it to `m` in `l` viewports -->
<gds-div padding="xs; l {m}">
  <!-- Similarly, here we default to 1 column, increase to 2 columns in `m` viewpors, and 4 columns in `xl` viewports -->
  <gds-grid columns="1; m {2}; xl {4}">
    <!-- Any HTML element can go as children -->
  </gds-grid>
</gds-div>
```

This is a very simple example, but it should give you an idea of how the style expression properties work.

Media queries can also be expressed as CSS units and as ranges, for example:

- `>m, <xl { ... }` - Above `m`, below `xl`
- `>500px, <1000px { ... }` - Above 500px, below 1000px

The value that goes in the media query is usually resolved to a css variable. In the padding example, it would
resolve to `var(--gds-sys-space-m)`. This is then transformed into a CSS property, typically of the same name as the
property used on the component. So, here it would be `padding: var(--gds-sys-space-m)`. That means you can also use
regular CSS shorthand patterns, like `padding: 1em 2em 3em 4em` by adding more values. They will each resolve to\
a CSS variable. For example: `padding="xs; l {m xl m xl}"`

The short names used in style expression properties (like `xs`, `m`, `l`, `xl`) correspond to design tokens. Each
property accepts tokens from a specific category — for example, `padding` accepts space tokens, while `background`
accepts color tokens. Check the API table for each component to see which token category a property accepts, and use
the `get_tokens` tool to discover all available token names and their resolved values.

When no media query is specified, it is the same as setting the breakpoint to 0. So, `padding="0 {m}"` is equivalent
to `padding="m"`.

### Pseudo selectors

Psudeo selectors can be added to any media query as a separate value sequence. For example:

```html
<gds-div padding="xs; hover: s; l { s; hover: m }">
  <!-- Any HTML element can go as children -->
</gds-div>
```

In the above example, the padding will be `xs` by default, `s` on hover, `m` in `l` viewports, and `m` on hover in `l` viewports.

## Other components

Style expression properties are not limited to the declarative layout components. In fact, they are a central part of the Green Core architecture, and is available in many components, wherever it makes sense. For example, on `<gds-button>` you can set the width using style expression syntax.

In the API-tables in Storybook, you can find more information about the available style expression properties for each component under a separate section.

## Conclusion

In conclusion, this system solves the conflict issue by injecting the CSS directly into the shadow DOM of the component,
and it solves the payload size issue by generating the CSS that is needed on the fly on the client side. It also solves
the version lock-in by using the same version scoping mechanism as the rest of the components in Green Core.

Internally, the style expression properties are using a custom property decorator which can be configured for different
needs on a per-property basis. This keeps the code size in the implementation to a minimum, while still allowing for a
sufficient level of flexibility.

To learn more about Declarative layout, and the syntax for style expression properties, head over to the [Declarative layout section on seb.io](https://seb.io/primitives/declarative-layout).