VS Code webviews
A webview should feel native to the editor. Keep Enma's structure, type, spacing, radius and numbers, but take colors from the user's VS Code theme. @enma/css/vscode.css maps every color role Enma needs onto VS Code's theme variables.
Load the styles
ts
// extension.ts
const css = (file: string) =>
panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, 'media', file));
panel.webview.html = `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; style-src ${panel.webview.cspSource}; font-src ${panel.webview.cspSource}; script-src 'nonce-${nonce}';">
<link rel="stylesheet" href="${css('enma.css')}">
<link rel="stylesheet" href="${css('vscode.css')}">
<link rel="stylesheet" href="${css('fonts/graphite.css')}">
</head>
<body data-enma="graphite" class="e-canvas">
<main id="app"></main>
<script nonce="${nonce}" src="${panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, 'media', 'main.js'))}"></script>
</body>
</html>`;
Copy enma.css, vscode.css and the fonts folder from @enma/css/dist into media/ at build time. Fonts load through asWebviewUri and must be allowed by font-src in the Content Security Policy.
Follow the editor's theme
VS Code adds vscode-dark, vscode-light or vscode-high-contrast to the body. Set data-theme from it, and again when it changes:
ts
// media/main.ts
const body = document.body;
const sync = () => (body.dataset.theme = body.classList.contains('vscode-light') ? 'light' : 'dark');
sync();
new MutationObserver(sync).observe(body, { attributes: true, attributeFilter: ['class'] });
What the mapping does
css
[data-enma='graphite'],
[data-enma='graphite'][data-theme],
[data-enma='graphite'] [data-theme]:not([data-enma]) {
--e-bg: var(--vscode-editor-background);
--e-surface: var(--vscode-sideBar-background);
--e-raised: var(--vscode-list-hoverBackground);
--e-field: var(--vscode-input-background);
--e-line: var(--vscode-panel-border);
--e-line-strong: var(--vscode-input-border, var(--vscode-panel-border));
--e-ink: var(--vscode-foreground);
--e-ink-2: var(--vscode-descriptionForeground);
--e-primary: var(--vscode-button-background);
--e-on-primary: var(--vscode-button-foreground);
--e-accent: var(--vscode-focusBorder);
--e-focus: var(--vscode-focusBorder);
}
Tips
- Use compact density:
smbuttons and fields, 13px text, tables for lists of things. - Numbers still use the number face (JetBrains Mono in Graphite) with tabular figures.
- Keep keyboard shortcuts out of VS Code's way; register commands in the extension instead of listening for global keys in the webview.
- High contrast themes: VS Code's variables already carry the contrast; don't add Enma shadows on top.