High-performance library for inlining CSS into HTML 'style' attributes
npx @tessl/cli install tessl/npm-css-inline--css-inline@0.17.0CSS Inline is a high-performance library for inlining CSS into HTML 'style' attributes. It's designed for scenarios such as preparing HTML emails or embedding HTML into third-party web pages where external stylesheets cannot be loaded.
npm install @css-inline/css-inlineimport { inline, inlineFragment, version } from "@css-inline/css-inline";For CommonJS:
const { inline, inlineFragment, version } = require("@css-inline/css-inline");For WebAssembly (browser):
import { initWasm, inline, inlineFragment, version } from "@css-inline/css-inline/wasm-binding";import { inline } from "@css-inline/css-inline";
// Inline CSS from a complete HTML document
const html = `
<html>
<head>
<style>h1 { color: blue; }</style>
</head>
<body>
<h1>Big Text</h1>
</body>
</html>
`;
const inlinedHtml = inline(html);
// Result: <html><head></head><body><h1 style="color: blue;">Big Text</h1></body></html>CSS Inline operates through two execution environments:
The library processes HTML documents by:
<style> and <link> tags (configurable)Complete HTML document processing that inlines CSS from <style> tags and external stylesheets referenced by <link> tags.
/**
* Inline CSS styles from <style> tags to matching elements in the HTML tree
* @param html - Complete HTML document to process
* @param options - Configuration options for inlining behavior
* @returns HTML document with CSS inlined into style attributes
*/
function inline(html: string, options?: Options | undefined | null): string;Usage Examples:
import { inline } from "@css-inline/css-inline";
// Basic inlining
const result = inline(`
<html>
<head>
<style>
h1 { color: red; }
p { font-size: 14px; }
</style>
</head>
<body>
<h1>Title</h1>
<p>Paragraph</p>
</body>
</html>
`);
// With external stylesheet
const resultWithExternalCSS = inline(`
<html>
<head>
<link href="styles.css" rel="stylesheet">
</head>
<body>
<h1>Title</h1>
</body>
</html>
`, { baseUrl: "file:///path/to/stylesheets/" });
// With caching for performance
const resultWithCache = inline(html, {
cache: { size: 10 },
loadRemoteStylesheets: true
});Process HTML fragments (partial HTML without full document structure) by applying provided CSS styles directly.
/**
* Inline CSS styles into an HTML fragment
* @param html - HTML fragment to process (no <html>, <head>, or <body> required)
* @param css - CSS styles to apply to the fragment
* @param options - Configuration options for inlining behavior
* @returns HTML fragment with CSS inlined into style attributes
*/
function inlineFragment(html: string, css: string, options?: Options | undefined | null): string;Usage Examples:
import { inlineFragment } from "@css-inline/css-inline";
// Process a fragment
const fragment = `
<main>
<h1>Hello</h1>
<section>
<p>Content here</p>
</section>
</main>
`;
const css = `
h1 { color: blue; }
p { color: red; font-size: 16px; }
`;
const result = inlineFragment(fragment, css);
// Result: <main><h1 style="color: blue;">Hello</h1><section><p style="color: red; font-size: 16px;">Content here</p></section></main>Get the current package version for debugging or compatibility checks.
/**
* Get the package version
* @returns Package version string
*/
function version(): string;Initialize the WebAssembly module before using WASM variant functions. Required for browser usage.
/**
* Initialize Wasm module (WASM variant only)
* @param module_or_path - WebAssembly Module or .wasm file URL
* @returns Promise that resolves when initialization is complete
* @throws Error if called multiple times
*/
function initWasm(module_or_path: Promise<InitInput> | InitInput): Promise<void>;Usage Example:
import { initWasm, inline } from "@css-inline/css-inline/wasm-binding";
import { promises as fs } from "fs";
// Initialize WASM module first (only once per session)
await initWasm(fs.readFile("path/to/index_bg.wasm"));
// Now use the API normally (no remote stylesheets or caching supported)
const result = inline(htmlContent);WASM Limitations:
interface Options {
/** Whether to inline CSS from "style" tags (default: true) */
inlineStyleTags?: boolean;
/** Keep "style" tags after inlining (default: false) */
keepStyleTags?: boolean;
/** Keep "link" tags after inlining (default: false) */
keepLinkTags?: boolean;
/** Base URL for resolving relative stylesheet URLs */
baseUrl?: string;
/** Whether remote stylesheets should be loaded (default: true) */
loadRemoteStylesheets?: boolean;
/** LRU cache for external stylesheets (Node.js only) */
cache?: StylesheetCache;
/** Additional CSS to inline beyond document styles */
extraCss?: string;
/** Pre-allocate HTML node capacity for performance (default: 32) */
preallocateNodeCapacity?: number;
}interface StylesheetCache {
/** Cache size - must be integer greater than zero */
size: number;
}interface InlineOptions {
/** Whether to inline CSS from "style" tags (default: true) */
inlineStyleTags?: boolean;
/** Keep "style" tags after inlining (default: false) */
keepStyleTags?: boolean;
/** Keep "link" tags after inlining (default: false) */
keepLinkTags?: boolean;
/** Keep "at-rules" like @media after inlining (default: false) */
keepAtRules?: boolean;
/** Base URL for resolving relative stylesheet URLs (limited support in WASM) */
baseUrl?: string;
/** Whether remote stylesheets should be loaded (NOT supported in WASM) */
loadRemoteStylesheets?: boolean;
/** Additional CSS to inline beyond document styles */
extraCss?: string;
/** Pre-allocate HTML node capacity for performance (default: 32) */
preallocateNodeCapacity?: number;
}
type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;Control inlining behavior per HTML element using data attributes:
<!-- Skip inlining for this element -->
<h1 data-css-inline="ignore">Won't receive styles</h1>
<!-- Keep the style tag (don't remove it) -->
<style data-css-inline="keep">h1 { color: blue; }</style>
<!-- Ignore this style tag entirely -->
<style data-css-inline="ignore">h1 { color: red; }</style>// Load stylesheets from local filesystem
const result = inline(html, {
baseUrl: "file:///path/to/project/",
loadRemoteStylesheets: true
});
// Load from remote URLs with caching
const result = inline(html, {
baseUrl: "https://example.com/assets/",
cache: { size: 5 }, // Cache up to 5 stylesheets
loadRemoteStylesheets: true
});
// Add extra CSS beyond document styles
const result = inline(html, {
extraCss: "body { margin: 0; padding: 0; }"
});// Pre-allocate capacity for large documents
const result = inline(html, {
preallocateNodeCapacity: 1000 // If you expect ~1000 HTML nodes
});
// Cache external stylesheets for performance
const result = inline(html, {
cache: { size: 10 }, // Cache up to 10 stylesheets
loadRemoteStylesheets: true
});The library throws errors with different behaviors depending on the execution environment:
baseUrl)try {
const result = inline(html, { baseUrl: "invalid-url" });
} catch (error) {
console.log(error.code); // "InvalidArg"
console.log(error.message); // "relative URL without a base: invalid-url"
}WASM variant throws string errors without structured codes:
try {
const result = inline(html, { baseUrl: "invalid-url" });
} catch (error) {
console.log(error); // "relative URL without a base: invalid-url"
}
// WASM-specific errors for unsupported operations
try {
const result = inline(`<link href="http://example.com/style.css" rel="stylesheet">`);
} catch (error) {
console.log(error); // "Loading remote stylesheets is not supported on WASM: http://example.com/style.css"
}Built on Mozilla Servo components, CSS Inline significantly outperforms JavaScript alternatives: