@arcmantle/vite-plugin-import-css-sheet
    Preparing search index...

    @arcmantle/vite-plugin-import-css-sheet

    @arcmantle/vite-plugin-import-css-sheet

    A Vite plugin that enables the use of TC39 Import Attributes proposal for CSS files. Import CSS files with with { type: 'css' } syntax and get them as CSSStyleSheet objects, perfect for Web Components and Shadow DOM.

    • 🚀 Import CSS as CSSStyleSheet: Transform CSS imports into constructable stylesheets
    • 🎯 TC39 Standard Syntax: Uses the official with { type: 'css' } syntax
    • Vite Integration: Seamless integration with Vite's build process
    • 🤖 Auto-Import: Automatically inject CSS imports for co-located stylesheets
    • 🗜️ CSS Minification: Built-in CSS minification using Lightning CSS
    • 🔧 Customizable: Support for custom transformers and additional code injection
    • 📦 TypeScript Support: Full TypeScript definitions included
    • 🔍 Development Friendly: Watch mode support for CSS file changes
    npm install @arcmantle/vite-plugin-import-css-sheet
    # or
    pnpm add @arcmantle/vite-plugin-import-css-sheet
    # or
    yarn add @arcmantle/vite-plugin-import-css-sheet

    Add the plugin to your vite.config.ts:

    import { defineConfig } from 'vite';
    import { importCSSSheet } from '@arcmantle/vite-plugin-import-css-sheet';

    export default defineConfig({
    plugins: [
    importCSSSheet()
    ]
    });

    Use the TC39 import attributes syntax to import CSS files as CSSStyleSheet objects:

    // Import CSS as CSSStyleSheet
    import styles from './component.css' with { type: 'css' };

    // Use with Web Components
    class MyComponent extends HTMLElement {
    constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });

    // Apply the stylesheet to shadow DOM
    shadow.adoptedStyleSheets = [styles];

    shadow.innerHTML = `
    <div class="container">
    <h1>Hello World</h1>
    </div>
    `;
    }
    }

    customElements.define('my-component', MyComponent);

    Perfect for Lit components:

    import { LitElement, html } from 'lit';
    import { customElement } from 'lit/decorators.js';
    import componentStyles from './component.css' with { type: 'css' };

    @customElement('my-lit-component')
    export class MyLitComponent extends LitElement {
    static styles = [componentStyles];

    render() {
    return html`
    <div class="container">
    <p>Styled with imported CSS sheet!</p>
    </div>
    `;
    }
    }

    Include the provided type definitions in your project:

    // In your vite-env.d.ts or types file
    /// <reference types="@arcmantle/vite-plugin-import-css-sheet/client" />

    This provides proper TypeScript support for CSS imports:

    // TypeScript will know this is a CSSStyleSheet
    import styles from './styles.css' with { type: 'css' };

    The plugin accepts several configuration options:

    import { importCSSSheet } from '@arcmantle/vite-plugin-import-css-sheet';

    export default defineConfig({
    plugins: [
    importCSSSheet({
    // Custom CSS transformers
    transformers: [
    (code, id) => {
    // Custom transformation logic
    return code.replace(/\$primary-color/g, '#007bff');
    }
    ],

    // Additional code to inject
    additionalCode: [
    'console.log("CSS sheet loaded:", sheet);'
    ],

    // Disable minification (enabled by default)
    minify: false
    })
    ]
    });
    Option Type Default Description
    transformers ((code: string, id: string) => string)[] [] Array of functions to transform CSS before converting to stylesheet
    additionalCode string[] [] Additional JavaScript code to inject into the generated module
    minify boolean true Whether to minify CSS using Lightning CSS
    autoImport object undefined Configuration for automatic CSS import injection

    The auto-import feature automatically detects when a .css file exists alongside your component file and automatically injects the import statement and adds it to your component's static styles property. This is perfect for component-based frameworks like Lit.

    When you have co-located CSS files:

    src/
      ├── my-component.ts
      └── my-component.css
    

    The plugin can automatically transform your component to include the CSS import, eliminating boilerplate.

    Enable auto-import by providing the autoImport configuration:

    import { importCSSSheet } from '@arcmantle/vite-plugin-import-css-sheet';

    export default defineConfig({
    plugins: [
    importCSSSheet({
    autoImport: {
    identifier: [
    {
    className: 'LitElement',
    styleName: 'styles',
    position: 'prepend' // or 'append'
    }
    ]
    }
    })
    ]
    });
    Property Type Required Description
    className string Yes The base class name to detect (e.g., 'LitElement', 'HTMLElement')
    styleName string Yes The static property name to inject the stylesheet into (e.g., 'styles')
    position 'prepend' | 'append' No Where to add the stylesheet in the array. Default: 'prepend'
    // my-component.ts
    import { LitElement, html } from 'lit';
    import { customElement } from 'lit/decorators.js';
    import componentStyles from './my-component.css' with { type: 'css' };

    @customElement('my-component')
    export class MyComponent extends LitElement {
    static styles = [componentStyles]; // Manually added

    render() {
    return html`<div>Hello World</div>`;
    }
    }

    With auto-import enabled, you can omit the import and static property:

    // my-component.ts
    import { LitElement, html } from 'lit';
    import { customElement } from 'lit/decorators.js';
    // Import is automatically injected!

    @customElement('my-component')
    export class MyComponent extends LitElement {
    // static styles is automatically created/updated!

    render() {
    return html`<div>Hello World</div>`;
    }
    }

    The plugin automatically transforms this to:

    import my_component_styles from './my-component.css' with { type: 'css' };
    import { LitElement, html } from 'lit';
    import { customElement } from 'lit/decorators.js';

    @customElement('my-component')
    export class MyComponent extends LitElement {
    static styles = [my_component_styles]; // Auto-injected!

    render() {
    return html`<div>Hello World</div>`;
    }
    }

    If you already have a static styles property, the auto-import will add to it:

    // Before transformation
    import { LitElement } from 'lit';
    import sharedStyles from './shared.css' with { type: 'css' };

    export class MyComponent extends LitElement {
    static styles = [sharedStyles];
    }

    // After transformation (with position: 'prepend')
    import my_component_styles from './my-component.css' with { type: 'css' };
    import { LitElement } from 'lit';
    import sharedStyles from './shared.css' with { type: 'css' };

    export class MyComponent extends LitElement {
    static styles = [my_component_styles, sharedStyles]; // Prepended
    }

    // After transformation (with position: 'append')
    export class MyComponent extends LitElement {
    static styles = [sharedStyles, my_component_styles]; // Appended
    }

    You can configure auto-import for multiple base classes:

    importCSSSheet({
    autoImport: {
    identifier: [
    {
    className: 'LitElement',
    styleName: 'styles',
    position: 'prepend'
    },
    {
    className: 'CustomBaseElement',
    styleName: 'styleSheets',
    position: 'append'
    },
    {
    className: 'MyFrameworkComponent',
    styleName: 'componentStyles'
    }
    ]
    }
    })

    The auto-import feature only activates when:

    1. A .css file exists with the same name as your component file
    2. Your class extends one of the configured base classes
    3. The file is a supported type (.ts, .tsx, .js, .jsx, .mts, .mjs)

    The position option controls CSS cascade order:

    • prepend (default): Component styles come first, can be overridden by later styles
    • append: Component styles come last, override earlier styles
    // position: 'prepend'
    static styles = [componentStyles, baseStyles, themeStyles];
    // ^^^^^^^^^^^^^^ auto-imported (lowest specificity)

    // position: 'append'
    static styles = [baseStyles, themeStyles, componentStyles];
    // ^^^^^^^^^^^^^^ auto-imported (highest specificity)

    Less Boilerplate: No need to manually import and assign stylesheets ✅ Co-location: Encourages keeping styles next to components ✅ Consistency: Automatic naming conventions ✅ Flexibility: Works with existing manual imports ✅ Type-Safe: Full TypeScript support with source maps

    1. Detection: The plugin scans your source files for CSS imports using the with { type: 'css' } syntax
    2. Virtual Modules: Creates virtual modules for CSS files that need to be converted
    3. Transformation: Processes CSS through any custom transformers and minification
    4. Code Generation: Generates JavaScript code that creates a CSSStyleSheet object
    5. Export: Exports the stylesheet as the default export

    This plugin generates code that uses the Constructable Stylesheets API:

    • Chrome/Edge 73+
    • Firefox 101+
    • Safari 16.4+

    For older browsers, consider using a polyfill.

    // Traditional Vite CSS import (injects into document)
    import './styles.css';
    // Get CSS as CSSStyleSheet object
    import styles from './styles.css' with { type: 'css' };

    // Perfect for Shadow DOM
    shadowRoot.adoptedStyleSheets = [styles];
    • Encapsulation: Styles don't leak into global scope
    • Performance: No style injection/removal overhead
    • Standards Compliant: Uses official TC39 syntax
    • Shadow DOM Ready: Perfect for Web Components
    • Tree Shakable: Only load styles when needed
    import baseStyles from './base.css' with { type: 'css' };
    import themeStyles from './theme.css' with { type: 'css' };
    import componentStyles from './component.css' with { type: 'css' };

    // Combine multiple stylesheets
    element.shadowRoot.adoptedStyleSheets = [
    baseStyles,
    themeStyles,
    componentStyles
    ];
    // Conditional style loading
    const isDark = document.body.classList.contains('dark-theme');
    const themeStyles = isDark
    ? await import('./dark-theme.css' with { type: 'css' })
    : await import('./light-theme.css' with { type: 'css' });

    shadowRoot.adoptedStyleSheets = [baseStyles, themeStyles.default];
    # Install dependencies
    pnpm install

    # Run demo in development mode
    pnpm dev

    # Build the plugin
    pnpm build
    • Node.js >= 22
    • Vite >= 7.0.0
    • lightningcss: Fast CSS transformer and minifier for CSS processing

    Apache-2.0

    This package is part of the Arcmantle Weave monorepo. Contributions are welcome! .......