Buildless Development
Write TypeScript and import CSS directly in your browser - no build step required. cem serve lets you develop without running tsc, CSS watchers, or bundlers.
Write TypeScript Directly
Import TypeScript files directly in your demos without compilation:
<!-- In your demo -->
<script type="module" src="../src/my-element.ts"></script>No need to:
- Run
tsc --watch - Set up a build pipeline
- Wait for compilation before testing
- Manage separate source and output directories
The dev server handles TypeScript on-demand with full source map support for debugging.
Browser Compatibility
Control which browsers your code supports using the --target flag:
cem serve --target es2020The default target is es2022. See
esbuild’s target documentation
for all available targets.
Your tsconfig.json Works
The dev server respects your existing TypeScript configuration:
compilerOptions.targetcompilerOptions.moduleincludeandexcludepatterns- Path mappings (via import maps)
--target flag overrides tsconfig.json settings.
Import CSS as Modules
Import CSS files directly in your components using modern CSS module syntax:
import styles from './my-element.css';
class MyElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [styles];
}
}No need to:
- Run CSS preprocessors or watchers
- Bundle stylesheets separately
- Use inline
<style>tags - Write CSS-in-JS template literals
Your imported CSS becomes a Constructable Stylesheet automatically, giving you better performance than inline styles.
Import Attributes (Modern Syntax)
Use the standard
import attributes
syntax with the with keyword:
import styles from './my-element.css' with { type: 'css' };
class MyElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [styles];
}
}This is the modern, standards-based syntax for importing CSS as modules. The dev server automatically handles this syntax during TypeScript transformation - import attributes are preserved and CSS files are transformed to JavaScript modules that export CSSStyleSheet objects.
with { type: 'css' } bypass include/exclude patterns. When you use this syntax, the dev server knows you want that CSS file transformed to a module, regardless of glob patterns.
How it works:
- You write:
import styles from './foo.css' with { type: 'css' } - The dev server rewrites it to:
import styles from './foo.css?__cem-import-attrs[type]=css' - When the browser requests the CSS file with those query parameters, the server transforms it to a JavaScript module
- Your code receives a ready-to-use
CSSStyleSheetobject
This approach works around esbuild’s current limitation with CSS import attributes while preserving the standard syntax in your source code.
Opt-In for Safety
CSS module transformation is opt-in to protect traditional <link> stylesheets. Specify which CSS files to transform:
Via command line:
# Transform component CSS only
cem serve --css-transform 'src/**/*.css' --css-transform 'elements/**/*.css'Via config file:
serve:
transforms:
css:
include:
- 'src/**/*.css'
- 'elements/**/*.css'
exclude:
- 'demo/**/*.css'Via import attributes:
// This CSS file will be transformed regardless of include/exclude patterns
import styles from './my-styles.css' with { type: 'css' };<link rel="stylesheet"> tags from breaking unexpectedly.
Example: CSS Module Import
Your CSS file:
/* my-element.css */
:host {
display: block;
color: var(--text-color, #333);
}Import it:
import styles from './my-element.css';
class MyElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [styles];
}
}What you get:
A CSSStyleSheet object ready to use with adoptedStyleSheets - no build step, no runtime CSS parsing.
What Works Without Building
You can use directly:
- TypeScript files (
.ts,.tsx) - CSS files as modules (with opt-in patterns)
- ES modules from npm via import maps
- Modern JavaScript syntax
You still write as-is:
- JavaScript files (
.js,.mjs) - HTML files
- JSON files
Debugging
Source maps work automatically:
- Stack traces point to your original TypeScript
- Browser DevTools show your source files
- Breakpoints work in TypeScript, not generated JavaScript
Configuration
Via Command Line
cem serve --target es2020 --css-transform 'src/**/*.css'Via Config File
serve:
target: es2020
transforms:
css:
include:
- 'src/**/*.css'See Configuration for all options.
What’s Next?
- Import Maps - Use npm packages without bundling
- Configuration - Configuration reference
- Getting Started - Set up your first demo