Mesa guide / Styling
Scoped styles
A <style> block belongs to its component. Its rules apply to that component's
own elements and nothing else.
<script>
let count = 0
</script>
<button onclick={() => count++}>
Clicked {count} times
</button>
<style>
button {
color: white;
background: rebeccapurple;
}
</style>
The compiler puts a content-addressed class on every element in the component
and on the end of every selector, so button becomes button.mHASH. Other
components' buttons are untouched.
The class goes on the subject
The scope class is appended to the rightmost part of a selector, the thing the rule actually styles. Two things follow:
- You can style your own root. A rule for the component's outermost element matches it.
- You cannot style a child component's elements. They carry the child's class, not yours.
To cross that boundary on purpose, wrap the selector in :global(...):
.card :global(.badge) { color: red }
:global(...), :root, html and body are emitted unscoped.
Tag selectors and <mesa:element>
A tag selector cannot match a <mesa:element>,
whose tag is only known at run time. Match it on a class.
When styles do not appear
Through the Vite plugin, scoped styles are injected for you. If you call the
compiler yourself with css: false, the styles come back on ctx.css.result
and you must inject them: the markup still carries the class and matches no
rule. See the compiler reference.
Mesa does not ship a design system. For tones, treatments and tokens, see
@frontierjs/css, the styling language for
FrontierJS apps.
Spec: VISION.md § 5 · RULE 55