A short walkthrough: HTML structure, FSCSS for layout and chrome, then optional polish with tokens and the form module. Everything compiles to plain CSS.
1. Markup first
Keep the form boring and accessible. FSCSS does not replace labels or name attributes.
<form class="contact" action="#" method="post">
<h1 class="contact__title">Contact</h1>
<p class="contact__lead">We’ll reply within one business day.</p>
<label class="field">
<span class="field__label">Name</span>
<input class="field__input" type="text" name="name" autocomplete="name" required>
</label>
<label class="field">
<span class="field__label">Email</span>
<input class="field__input" type="email" name="email" autocomplete="email" required>
</label>
<label class="field">
<span class="field__label">Message</span>
<textarea class="field__input field__input--area" name="message" rows="4" required></textarea>
</label>
<button class="btn" type="submit">Send</button>
</form>
2. Load FSCSS
Prototype (CDN runtime):
<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.6/runtime.min.js" defer></script>
<link type="text/fscss" href="form-page.fscss">
Or compile:
npm install -g fscss@1.2.6
fscss form-page.fscss form-page.css
<link rel="stylesheet" href="form-page.css">
3. Style with layout helpers and tokens
stack, px / py, rounded, and friends (1.2.5+) keep the sheet short. See shorthands.
/* form-page.fscss */
:root {
--bg: #0b1020;
--surface: #121a30;
--border: #22304f;
--text: #e6edf7;
--muted: #9fb0d0;
--accent: #6366f1;
--radius: 12px;
}
body {
m: 0;
min-h: 100vh;
center: both;
p: 24px;
bg: var(--bg);
color: var(--text);
ff: system-ui, sans-serif;
}
.contact {
w: 100%;
max-w: 400px;
stack: 16px;
p: 24px;
bg: var(--surface);
border: 1px solid var(--border);
rounded: 16px;
}
.contact__title {
m: 0;
fs: 1.35rem;
}
.contact__lead {
m: 0;
color: var(--muted);
fs: 0.9rem;
}
.field {
stack: 6px;
}
.field__label {
fs: 0.8rem;
color: var(--muted);
}
.field__input {
w: 100%;
px: 12px;
py: 10px;
rounded: var(--radius);
border: 1px solid var(--border);
bg: #0a0f1e;
color: var(--text);
font: inherit;
}
.field__input:focus {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.field__input--area {
resize: vertical;
min-h: 100px;
}
.btn {
mt: 4px;
px: 16px;
py: 10px;
border: 0;
rounded: var(--radius);
bg: var(--accent);
color: #fff;
font: inherit;
fw: 600;
cur: pointer;
}
.btn:hover {
filter: brightness(1.08);
}
What you get after compile: normal flex column + gap, axis padding, radius, and colors—no framework runtime.
4. Optional: reusable button with @define
@define btn(bg: #6366f1){`
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 16px;
border: 0;
border-radius: var(--radius, 12px);
background: @use(bg);
color: #fff;
font-weight: 600;
cursor: pointer;
`}
.btn {
@btn(var(--accent))
}
.btn-ghost {
@btn(transparent)
border: 1px solid var(--border);
color: var(--text);
}
5. Optional: form.fscss module
When you want float labels and shared field chrome instead of hand-rolled classes:
@import((form-root, form-group, form-input, form-label, form-float, form-btn-primary) from form)
@form-root()
@form-float(.form-group, .form-input, .form-label)
Markup pattern (input before label, placeholder=" " for :placeholder-shown tricks) is documented with the module. Use selective imports so you only pull what the page needs.
6. Optional: semantic styling with pattern() (1.2.4+)
pattern(0.55: "soft dark form card", `
background: #121a30;
border: 1px solid #22304f;
border-radius: 16px;
padding: 24px;
`)
.contact {
soft dark form card
stack: 16px;
max-w: 400px;
}
Good for role-based phrases; keep critical layout in explicit rules so the form stays predictable.
7. Try it in the IDE
- Open fscss.devtem.org/ide
- Paste the HTML into an
index.htmland the FSCSS intoform-page.fscss - Ctrl+Enter to compile, preview to check focus states
- Export when you’re ready
Checklist
- Labels associated with controls (wrapping
<label>orfor/id) -
:focusstyles visible on keyboard - Tokens on
:rootso themes don’t require rewriting fields - Production: compiled CSS only, not the runtime
- Shorthands: https://fscss.devtem.org/shorthands
- Docs: https://fscss.devtem.org/docs
- IDE: https://fscss.devtem.org/ide
- npm:
fscss@1.2.6
A simple contact form is a good first FSCSS page: one column (stack), a few fields, one button—and the same file can grow into tokens, @define, or a form module without changing the HTML structure.
Top comments (0)