Appearance
Feature SDK
Import from @favn/feature-sdk to interact with host runtime APIs.
Bootstrap
js
import { getBootstrapConfig, getMountElement } from '@favn/feature-sdk';
const config = getBootstrapConfig();
// { featureId, version, basename, domElementId, hostVersion }
const container = getMountElement(config.domElementId);
// Returns the correct mount element (handles Shadow DOM automatically)Host API
js
import { createFeatureHostApi } from '@favn/feature-sdk';
const api = createFeatureHostApi('feature-my-feature');Event Bus
Publish events to other features and subscribe to cross-feature communication:
js
// Publish
api.eventBus.publish('my-feature', 'patient-selected', { id: '123' });
// Subscribe
const unsub = api.eventBus.subscribe('navigation', 'route-changed', (event) => {
console.log('Route changed:', event);
});
// Call unsub() to unsubscribeHost Store
Read and write shared global state:
js
// Read
const locale = api.store.get('locale', 'en');
const theme = api.store.get('theme', 'light');
// Write
api.store.set('locale', 'nb');
// Subscribe to changes
const unsub = api.store.onChange('locale', (value) => {
console.log('Locale changed:', value);
});Lifecycle
Register cleanup handlers and track timers:
js
// Runs when the host unmounts your feature
api.lifecycle.onCleanup(() => {
console.log('Cleaning up...');
});
// Auto-cleared on unmount
api.lifecycle.trackInterval(
setInterval(() => console.log('tick'), 1000)
);Shadow DOM
If your feature needs CSS isolation, set isolation.shadowDOM: true in your manifest.
js
import { getFeatureShadowRoot } from '@favn/feature-sdk';
const shadowRoot = getFeatureShadowRoot();
// null if Shadow DOM is not enabled
// ShadowRoot if enabled — use for dynamic style injectionWhen Shadow DOM is enabled:
- Your CSS files are injected into the shadow root (not
<head>) getMountElement()returns the inner element inside the shadow root- Global styles from the host won't affect your feature
- Your styles won't leak to other features
Capability enforcement
The host wraps all runtime APIs to enforce your manifest's runtime.permissions declarations. Denied operations:
- Log warnings in browser console
- Return safe values (
false,noop,undefined) rather than throwing
Reusable modules
The host also exposes a module registry for featureType: "facet" manifests ("module" alias is also accepted).
js
import { listModules, mountModule, unmountModule } from '@favn/feature-sdk';
const modules = listModules();
// [{ id, displayName, version, entrypoint, mountExport, unmountExport, ... }]
const target = document.querySelector('#summary-slot');
await mountModule('feature-summary-module', target, {
patientId: '123',
locale: 'nb-NO',
});
// Later
await unmountModule('feature-summary-module', target);Module contract:
mountExportdefaults tomountunmountExportdefaults tounmountmountModule()calls the mount export with(target, props)unmountModule()calls the unmount export with(target, mountHandle)