Skip to content

How to: style a component

You need to style a native view and want the shortest path for your framework.

A standalone .css/.module.css file import (className on React, class/[class] on Vue/Angular/Svelte/Solid) works identically on every adapter — this is what every current example app (examples/react, examples/vue-sfc, examples/vue-tsx, examples/angular, examples/svelte, examples/solid) actually does:

import './App.css';
<view className="card">
<text>Native surface</text>
</view>;

@symbiote-native/css-parser compiles the rule at build time; className="card" resolves it back at render time through a runtime class registry shared by every adapter. Plain CSS, CSS Modules, plus optional SCSS/Sass, Less, and Stylus preprocessing (<style lang="scss">, .module.scss, …) — no media queries and no pseudo-classes, save :active, which survives because a press is the one state the engine tracks itself (Styling guide). :hover and :focus have nothing to match and are dropped.

Vue and Svelte also get an inline <style> block

Section titled “Vue and Svelte also get an inline <style> block”

A Vue SFC <style> block (including scoped) and a Svelte component’s own <style> block both compile to the same native style objects at build time — no CSS ships in the bundle, no runtime CSS engine exists. Vue’s scoping is opt-in via the scoped attribute; Svelte’s is on by default, no attribute needed:

<template>
<view class="card"><text>Native surface</text></view>
</template>
<style scoped>
.card {
padding: 16px;
border-radius: 12px;
background-color: #111827;
}
</style>
<view class="card"><text>Native surface</text></view>
<style>
.card {
padding: 16px;
border-radius: 12px;
background-color: #111827;
}
</style>

Every adapter re-exports StyleSheet from @symbiote-native/engine. It’s still fully supported and needs no build-time CSS step — reach for it for a value that’s genuinely computed at runtime, or if you’d rather skip CSS entirely:

import { StyleSheet } from '@symbiote-native/react';
const styles = StyleSheet.create({
card: { padding: 16, borderRadius: 12, backgroundColor: '#111827' },
});
<view style={styles.card}>
<text>Native surface</text>
</view>;

StyleSheet.create() is identity at runtime — the engine flattens plain objects too. Its value is preserving literal types and giving the file one predictable style block at the bottom, not a different rendering path from CSS.

A bare .module.css import type-checks as Record<string, string> unless you wire two pieces from @symbiote-native/css-parser — add it as a devDependency:

Terminal window
pnpm add -D @symbiote-native/css-parser
package.json
{ "scripts": { "pretypecheck": "css-dts ." } }
tsconfig.json
{
"compilerOptions": {
"plugins": [{ "name": "@symbiote-native/css-parser/typescript-plugin" }]
}
}

pretypecheck’s css-dts . writes a real, narrowed .d.ts next to every .module.css file so a typo fails tsc; the typescript-plugin gives you matching autocomplete live in the editor, no watch process needed. See the Styling guide for what each piece covers.

  • Want CSS syntax → a standalone .css/.module.css file import works on every adapter; Vue and Svelte additionally support an inline <style> block, which reads more like ordinary Vue or Svelte.
  • Want inline, type-checked style objects with no separate file → StyleSheet.create works identically on every adapter.

For the full model (what compiles, what doesn’t, the :global() escape hatch, CSS Modules status), see the Styling guide.