Styling HTML Elements
Inline vs. Stylesheet
For those new to web dev, it's worth understanding that there are two ways to set styles on your HTML elements: inline and stylesheet.
Inline styles are defined on the element tag itself. In raw HTML, this might look like:
Meanwhile, any given HTML page can reference a list of stylesheets which can define a bunch of styles, where each style is tied to a selector (a rule which selects what elements those styles apply to).
A concrete example of a very short stylesheet can help here:
And you could use that stylesheet to style the following document:
When conflicting styles are present both in a stylesheet and as an inline declaration, the inline styles take precedence.
We introduce and discuss both modifiers ( Modifier) and CSS style blocks ( CssStyle) later. But in general, when you pass modifiers directly as an argument into a composable widget, those will result in inline styles, whereas if you use a CSS style block to define your styles, those will get embedded into the site's stylesheet:
Stylesheet advantages
There's no hard and fast rule, but in general, when writing HTML / CSS by hand, stylesheets are often preferred over inline styles as it better maintains a separation of concerns. That is, the HTML should represent the content of your site, while the CSS controls the look and feel.
However! We're not writing HTML / CSS by hand. We're using Compose HTML! Should we even care about this in Kotlin?
As it turns out, there are times when you have to use stylesheets, because without them, you can't define styles for advanced behaviors (particularly pseudo-classes, pseudo-elements, and media queries). For example, you can't override the color of visited links without using a stylesheet approach. So it's worth realizing there are fundamental differences.
Finally, it can also be much easier debugging your page with browser tools when you lean on stylesheets over inline styles, as it makes your DOM tree easier to read when your elements are simple (e.g. <div class="title">
vs. <div style="color:yellow; background-color:black; font-size: 24px; ...">
).
Which to use?
As a beginner, or even as an advanced user when prototyping, feel free to use inline modifiers as much as you can, pivoting to CSS style blocks if you find yourself needing to use pseudo-classes, pseudo-elements, or media queries. It is fairly easy to migrate inline styles over to stylesheets in Kobweb.
In my own projects, I tend to use inline styles for really simple layout declarations (e.g. Row(Modifier.fillMaxWidth())
) and CSS style blocks for complex and/or re-usable widgets.
Modifier
Kobweb introduces the Modifier
class, in order to provide an experience similar to what you find in Jetpack Compose. (You can read more about them here if you're unfamiliar with the concept).
In the world of Compose HTML, you can think of a Modifier
as a wrapper on top of CSS styles and some attributes.
Please refer to official documentation if you are not familiar with HTML attributes and/or styles.
So this:
when passed into a widget provided by Kobweb, like Box
:
would generate HTML equivalent to:
Chaining
Like in Jetpack Compose, modifiers can be chained together using the then
method:
Since modifiers are immutable, you can reuse and combine them fearlessly.
toAttrs
Modifier
is a Kobweb concept, but Compose HTML doesn't know anything about it. It works with a concept called AttrsScope
for declaring attributes and styles.
Therefore, if you have a Modifier
that you want to pass into a Compose HTML element, you can convert it to an AttrsScope
using the toAttrs
method:
You can additionally pass in a callback to toAttrs
which lets you modify the final AttrsScope
, typed to the current element:
For example, you could use this when working with the Compose HTML Input
composable to add input-specific attributes:
attrsModifier
and styleModifier
There are a bunch of modifier extensions (and they're growing) provided by Kobweb, like background
, color
, and padding
above. But there are also two escape hatches anytime you run into a modifier that's missing: attrsModifier
and styleModifier
.
At this point, you are interacting with Compose HTML, one layer underneath Kobweb.
Using them looks like this:
Note that style
itself is an attribute, so you can even define styles in an attrsModifier
:
but in the above case, you are encouraged to use a styleModifier
instead for simplicity.
attr
and property
In the occasional (and hopefully rare!) case where Kobweb doesn't provide a modifier and Compose HTML doesn't provide the attribute or style support you need, you can use attrsModifier
plus the attr
method or styleModifier
plus the property
method. This escape hatch within an escape hatch allows you to provide any custom value you need.
The above cases can be rewritten as:
Finally, note that styles are, by the design of CSS, applicable to any element, while attributes are often tied to specific ones. For example, the id
attribute can be applied to any element, but href
can only be applied to an a
tag. Since modifiers don't have context of which element they're being passed into, Kobweb only aims to provide attribute modifiers for global attributes (e.g. Modifier.id("example")
) and no others.
If you ever end up needing to use styleModifier { property(key, value) }
in your own codebase, consider letting us know so that we can add the missing style modifier to the framework.
At the very least, you are encouraged to define your own extension method to create your own type-safe style modifier: