Captcha Styling
The same MochiCaptcha four times over. Every colour is a CSS custom property with a built-in fallback, so styling it is CSS — no props, no theme object, no wrapper component.
Set the --mochi-captcha-* vars on any ancestor and they inherit down into the widget. The emoji and label props cover the rest. Each one below
is live — slide any of them.
Defaults
No CSS at all. The widget ships light-mode defaults in each var() fallback, so it looks finished out of the box.
<MochiCaptcha {...captcha} />/* Each var's built-in fallback. */
:root {
--mochi-captcha-accent: #4a7c59;
--mochi-captcha-accent-soft: #e0ebe1;
--mochi-captcha-accent-soft-text: #2f5b3f;
--mochi-captcha-border: #e8e4d8;
--mochi-captcha-track-bg: #faf8f1;
--mochi-captcha-handle-bg: #fffdf8;
--mochi-captcha-handle-text: var(--mochi-captcha-accent);
--mochi-captcha-hint-text: #6e756d;
--mochi-captcha-radius: 999px;
}Themed
Map the vars onto your palette. These point at this site's tokens, so this one follows the light/dark toggle.
<MochiCaptcha
{...captcha}
emoji="🍡"
label="Slide the mochi to the right"
verifyingLabel="Steaming…"
verifiedLabel="Freshly made — thanks!"
/>.themed {
--mochi-captcha-accent: var(--accent);
--mochi-captcha-accent-soft: var(--accent-soft);
--mochi-captcha-accent-soft-text: var(--accent-soft-text);
--mochi-captcha-border: var(--border);
--mochi-captcha-track-bg: var(--surface-muted);
--mochi-captcha-handle-bg: var(--surface);
--mochi-captcha-hint-text: var(--text-subtle);
}Candy
The vars are just colours — hand them anything, including gradients.
<MochiCaptcha
{...captcha}
emoji="🍭"
label="Slide for a tasty treat"
verifyingLabel="Unwrapping…"
verifiedLabel="Enjoy your sweet!"
/>.candy {
--mochi-captcha-accent: #d6336c;
--mochi-captcha-accent-soft: linear-gradient(90deg, #ffd6e7, #ffa8cd);
--mochi-captcha-accent-soft-text: #a61e4d;
--mochi-captcha-border: #ffa8cd;
--mochi-captcha-track-bg: #fff0f6;
--mochi-captcha-handle-bg: #fff;
--mochi-captcha-hint-text: #c2255c;
}Terminal
Square off the corners with --mochi-captcha-radius for a different silhouette.
<MochiCaptcha
{...captcha}
emoji="▶"
label="SLIDE TO PROVE HUMANITY"
verifyingLabel="VERIFYING…"
verifiedLabel="ACCESS GRANTED"
/>.terminal {
--mochi-captcha-radius: 0;
--mochi-captcha-accent: #33ff77;
--mochi-captcha-accent-soft: #04301a;
--mochi-captcha-accent-soft-text: #33ff77;
--mochi-captcha-border: #33ff77;
--mochi-captcha-track-bg: #04150c;
--mochi-captcha-handle-bg: #04301a;
--mochi-captcha-hint-text: #2bbd5a;
font-family: var(--font-mono);
}<script lang="ts">
import StylingDemo from './StylingDemo.svelte';
import { files } from './files.ts';
import { themes, defaultsSample, rule, markup } from './themes.ts';
import { highlightCode } from '../../lib/highlight.server';
import type { MintedCaptcha } from 'mochi-framework';
let { captchas }: { captchas: MintedCaptcha[] } = $props();
// Highlighted here rather than in the island: Shiki is server-only.
const css = {
defaults: await highlightCode(defaultsSample, 'css'),
themed: await highlightCode(rule('.themed', themes.themed.css), 'css'),
candy: await highlightCode(rule('.candy', themes.candy.css), 'css'),
terminal: await highlightCode(rule('.terminal', themes.terminal.css), 'css'),
};
const svelte = {
defaults: await highlightCode('<MochiCaptcha {...captcha} />', 'svelte'),
themed: await highlightCode(markup(themes.themed), 'svelte'),
candy: await highlightCode(markup(themes.candy), 'svelte'),
terminal: await highlightCode(markup(themes.terminal), 'svelte'),
};
const sources = await loadSources(files);
</script>
<p>
Set the <code>--mochi-captcha-*</code> vars on any ancestor and they inherit down into the widget. The <code>emoji</code> and <code>label</code> props cover the rest. Each one below
is live — slide any of them.
</p>
<StylingDemo mochi:hydrate {captchas} {css} {svelte} />
Styles
<style>
p {
margin: 0 0 0.5rem;
font-size: 0.9rem;
color: var(--text-muted);
}
code {
background: var(--code-bg);
color: var(--code-accent);
padding: 0.05rem 0.35rem;
border-radius: var(--radius-sm);
font-family: var(--font-mono);
font-size: 0.85rem;
}
</style>
More demos