Skip to main content
Version: v5 (Preview)

Standalone Output Target

note

Renamed from dist-custom-elements in Stencil v4. Run stencil migrate --dry-run to preview updating an existing config automatically.

The standalone output target creates custom elements that directly extend HTMLElement and provides simple utility functions for easily defining these elements on the Custom Element Registry. Each component compiles to its own file with determinative filenames; a consuming project's own bundler only includes the ones it actually imports making it better suited to frameworks and any project that already takes care of bundling and lazy-loading itself.

Standalone components can be cherry-picked and defined individually, bundled and defined all at once, or defined automatically via the auto-loader as they appear in the DOM - see Consumption below. See Choosing Between loader-bundle and standalone for when each output target is the better fit.

Publishing this output requires the right package.json fields pointing at it - see Standalone in the publishing guide for the exact exports map.

To generate components using the standalone output target, add it to a project's stencil.config.ts file like so:

stencil.config.ts
import { Config } from '@stencil/core';

export const config: Config = {
// Other top-level config options here
outputTargets: [
{
type: 'standalone',
// Output target config options here
},
// Other output targets here
],
};

Config​

copy​

default: undefined

An array of copy tasks to be executed during the build process.

customElementsExportBehavior​

default: 'default'

By default, the standalone output target generates a single file per component, and exports each of those files individually.

In some cases, library authors may want to change this behavior, for instance to automatically define component children, provide a single file containing all component exports, etc.

This config option provides additional behaviors that will alter the default component export OR custom element definition behaviors for this target. The desired behavior can be set via the following in a project's Stencil config:

// stencil.config.ts
import { Config } from '@stencil/core';

export const config: Config = {
outputTargets: [
{
type: 'standalone',
customElementsExportBehavior: 'default' | 'auto-define-custom-elements' | 'bundle' | 'single-export-module',
},
// ...
],
// ...
};
OptionDescription
defaultNo additional re-export or auto-definition behavior will be performed.

This value will be used if no explicit value is set in the config, or if a given value is not a valid option.
auto-define-custom-elementsA component and its children will be automatically defined with the CustomElementRegistry when the component's module is imported.
bundleA utility defineCustomElements() function is exported from the index.js file of the output directory. This function can be used to quickly define all Stencil components in a project on the custom elements registry.
single-export-moduleAll component and custom element definition helper functions will be exported from the index.js file in the output directory. This file can be used as the root module when distributing your component library, see Publishing for more details.
note

At this time, components that do not use JSX cannot be automatically defined. This is a known limitation of Stencil that users should be aware of.

autoLoader​

default: true

Generates an auto-loader script that uses a MutationObserver to lazily load and define custom elements as they appear in the DOM - a loader.js file that auto-starts on import.

Set to false to skip generating it, or pass an object for more control:

outputTargets: [
{
type: 'standalone',
autoLoader: {
fileName: 'my-loader.js', // default: 'loader.js'
autoStart: false, // default: true - call start() yourself if false
},
},
]

loader.js also exports setRegistry, setTagTransformer, setNonce and setPlatformOptions. With autoStart: false, call them before start():

import { setRegistry, start } from 'my-library/dist/standalone/loader.js';

setRegistry(registry);
start();

dir​

default: 'dist/standalone'

This config option allows you to change the output directory where the compiled output for this output target will be written.

empty​

default: true

Setting this flag to true will remove the contents of the output directory between builds.

externalRuntime​

default: false

Setting this flag to true marks all imports from @stencil/core/* as external, so they're not included in the generated bundle - consumers must provide @stencil/core themselves. It has no effect on minification or file naming; standalone output is never filename-hashed, regardless of this setting.

note

As of Stencil v5, component bundles are self-contained by default (externalRuntime: false) - the runtime is included as a local shared chunk. Set this to true only if you need multiple Stencil component libraries on the same page to share a single runtime instance, and ensure @stencil/core is included in your list of dependencies if you do - this is crucial to prevent any runtime errors.

includeGlobalScripts​

default: false

Setting this flag to true will include global scripts in the bundle and execute them once the bundle entry point in loaded.

minify​

default: follows the Stencil config's minifyJs option - minified in a production build, unminified in dev

Set this explicitly to true or false to override that default for this output target specifically.

skipInDev​

default: true if loader-bundle is also configured, else false

Skips this output target during development builds (--dev) to improve build times. If loader-bundle is configured too, standalone is treated as the secondary output and skipped in dev by default; with no loader-bundle, standalone is the primary output and builds in dev as well. Set this explicitly to override either default.

Consumption​

Your users can either install your library via npm and import the components they need, or load them directly from a CDN within a <script type="module"> tag.

Cherry-Picking Components​

Import and define only the components consumers use - each compiles to its own file, so a bundler only includes what's imported:

import { MyComponent, defineCustomElement } from 'my-library/my-component';

defineCustomElement();
// or define it yourself:
customElements.define('my-component', MyComponent);
note

A component's defineCustomElement() also defines any child components it depends on, so you rarely need to import and define those separately. If defining the class yourself with customElements.define() you must also make sure to define any child components too.

Bundling All Components​

Set customElementsExportBehavior: 'bundle' to register every component from a single call instead of one defineCustomElement() each:

import { defineCustomElements } from 'my-library';

defineCustomElements();

This defines every component immediately. loader-bundle exports a same-named defineCustomElements(), but that one lazy-loads each component's logic on first use - the two aren't interchangeable across output targets.

Auto-Loading Components​

With autoLoader, components register themselves as they appear in the DOM - no import or defineCustomElement call needed:

import 'my-library/dist/standalone/loader.js';

A MutationObserver watches the page and defines each custom element the first time it appears, at the cost of being less performant than loader-bundle's per-component lazy loading, which can statically analyze which components a page needs ahead of time.

Assets​

Component asset resolution works the same as every other output target - see the Assets guide for assetsDirs, getAssetPath(), setAssetPath(), and making the asset files themselves servable to a consumer using a bundler.