Styling
Use any CSS you like. For scoped styles written next to components, @velozjs/css gives you css, styled and the css prop.
Plain CSS works
Veloz renders real elements with real class attributes, so stylesheets, CSS modules and class-based libraries work as is. This site is styled with salve-css and its icons with salve-icons, both through plain classes.
import 'salve-css';
<button class="btn btn-soft">Save</button>@velozjs/css
npm install @velozjs/cssImport it once in your client entry. That import also enables the css prop.
import '@velozjs/css';css
A tagged template that returns a scoped class name. Top-level declarations apply to the class. Nested rules are always scoped: & marks where the class goes, and a rule without & applies to descendants. @media, @supports and @container scope their contents, and @keyframes / @font-face are kept as written.
import { css } from '@velozjs/css';
const card = css`
padding: 1.5rem;
border-radius: 12px;
&:hover { box-shadow: 0 4px 12px rgb(0 0 0 / 0.1); }
.title { font-weight: 600; } /* .v-xyz .title */
@media (min-width: 40em) { padding: 2rem; }
`;
<div class={card}>…</div>;styled
Creates a component with its styles. Function interpolations receive the props; when they read accessors, the class updates reactively.
import { styled } from '@velozjs/css';
const Button = styled('button')`
padding: 0.5rem 1rem;
border-radius: 999px;
background: ${(p: { tone?: 'danger' }) => (p.tone === 'danger' ? 'crimson' : 'royalblue')};
`;
<Button tone="danger" onClick={remove}>Delete</Button>;The css prop
An object of styles on any element. Nested selectors and at-rules work, and numbers get px except for unitless properties (opacity, zIndex, lineHeight...). The same applies to style objects.
<span
css={{
color: 'gray',
'&:hover': { color: 'black' },
'.icon': { marginInlineEnd: '0.25rem' },
'@media (min-width: 40em)': { fontSize: '1.25rem' },
}}
>
hint
</span>How it works
- Class names are hashes of the CSS (
v-1x2y3z), so identical styles share one class. - Styles go into a constructable stylesheet (
adoptedStyleSheets), falling back to one<style data-veloz-css>element. No inline<style>writes, which keeps it CSP-friendly. - During SSR, styles are collected and returned by
renderToStringascss; put them in<style data-veloz-css>and the client won't inject them again.