Components API#

Component creation and built-in components.

component#

Create a SignalX component.

TSX
function component<TCombined, TRef, TSlots>(
    setup: (ctx: ComponentSetupContext) => ViewFn | Promise<ViewFn>,
    options?: ComponentOptions
): ComponentFactory<TCombined, TRef, TSlots>;

Parameters#

NameTypeDescription
setup(ctx) => ViewFnSetup function receiving context
options.namestringComponent name for DevTools

Returns#

ComponentFactory - A function usable as a JSX element.

Setup Context#

PropertyTypeDescription
signaltypeof signalCreate reactive state
propsPropsAccessor<TProps>Reactive props
slotsSlotsObject<TSlots>Slot functions
emitEmitFn<TEvents>Emit custom events
elPlatformElementRoot element (after mount)
parentanyParent component
onMounted(fn) => voidRegister mount callback
onUnmounted(fn) => voidRegister unmount callback
onCreated(fn) => voidRegister creation callback
onUpdated(fn) => voidRegister update callback
expose(api) => voidExpose API to parent
update() => voidForce re-render

Examples#

TSX
import { component, type Define } from 'sigx';

type CardProps = 
    & Define.Prop<'title', string, true>
    & Define.Event<'close'>
    & Define.Slot<'default'>
    & Define.Slot<'footer'>;

const Card = component<CardProps>(({ props, slots, emit }) => {
    return () => (
        <div class="card">
            <header>
                {props.title}
                <button onClick={() => emit('close')}>×</button>
            </header>
            <main>{slots.default()}</main>
            {slots.footer?.()}
        </div>
    );
}, { name: 'Card' });

// Usage
<Card 
    title="Welcome" 
    onClose={() => setOpen(false)}
    slots={{
        footer: () => <button>OK</button>
    }}
>
    <p>Card content</p>
</Card>

Fragment#

Render children without a wrapper element.

TSX
const Fragment: Symbol;

Usage#

TSX
import { Fragment } from 'sigx';

// Using Fragment component
<Fragment>
    <li>Item 1</li>
    <li>Item 2</li>
</Fragment>

// Using short syntax
<>
    <li>Item 1</li>
    <li>Item 2</li>
</>

lazy#

Create a lazy-loaded component.

TSX
function lazy<T extends ComponentFactory>(
    loader: () => Promise<T | { default: T }>
): LazyComponentFactory<T>;

Parameters#

NameTypeDescription
loader() => Promise<Component>Dynamic import function

Returns#

LazyComponentFactory with:

  • preload(): Promise<T> - Start loading before render
  • isLoaded(): boolean - Check if loaded

Examples#

TSX
import { lazy, Suspense } from 'sigx';

const HeavyChart = lazy(() => import('./HeavyChart'));

// Basic usage
<Suspense fallback={<Spinner />}>
    <HeavyChart />
</Suspense>

// Preload on hover
<button onMouseEnter={() => HeavyChart.preload()}>
    Show Chart
</button>

// Check load status
if (HeavyChart.isLoaded()) {
    console.log('Ready');
}

Suspense#

Show fallback content while lazy components load.

TSX
const Suspense: ComponentFactory<SuspenseProps>;

Props#

NameTypeDescription
fallbackJSXElement | () => JSXElementContent while loading

Examples#

TSX
import { lazy, Suspense } from 'sigx';

const Dashboard = lazy(() => import('./Dashboard'));

// Static fallback
<Suspense fallback={<div>Loading...</div>}>
    <Dashboard />
</Suspense>

// Dynamic fallback
<Suspense fallback={() => <Spinner size={size} />}>
    <Dashboard />
</Suspense>

// Multiple lazy components
<Suspense fallback={<Loading />}>
    <LazyHeader />
    <LazyContent />
</Suspense>

Portal#

Render children to a different DOM location.

TSX
const Portal: ComponentFactory<PortalProps>;

Props#

NameTypeDefaultDescription
tostring | Elementdocument.bodyTarget container
disabledbooleanfalseRender in-place instead

Examples#

TSX
import { Portal } from 'sigx';

// Render to body (default)
<Portal>
    <div class="modal">Modal content</div>
</Portal>

// Render to specific element
<Portal to="#modal-root">
    <div class="modal">Modal content</div>
</Portal>

// Render to element reference
<Portal to={containerElement}>
    <Tooltip />
</Portal>

// Conditional portal
<Portal disabled={inline}>
    <Dropdown />
</Portal>

isLazyComponent#

Check if a component is lazy-loaded.

TSX
function isLazyComponent(component: any): component is LazyComponentFactory;

Examples#

TSX
import { lazy, isLazyComponent } from 'sigx';

const LazyComp = lazy(() => import('./Comp'));
const RegularComp = component(() => () => <div />);

isLazyComponent(LazyComp);    // true
isLazyComponent(RegularComp); // false

getCurrentInstance#

Get the current component's setup context.

TSX
function getCurrentInstance(): ComponentSetupContext | null;

Returns#

The current component context, or null if not in a component.

Examples#

TSX
import { getCurrentInstance } from 'sigx';

function useCustomHook() {
    const ctx = getCurrentInstance();
    if (!ctx) {
        throw new Error('Must be called in component setup');
    }
    
    ctx.onMounted(() => {
        console.log('Component mounted');
    });
}

Helper Functions#

supportsMoveBefore#

Check if browser supports state-preserving DOM moves.

TSX
function supportsMoveBefore(): boolean;

moveNode#

Move a DOM node with state preservation when available.

TSX
function moveNode(
    parent: Element,
    node: Node,
    anchor?: Node | null
): void;

Types#

ComponentFactory#

TSX
type ComponentFactory<TCombined, TRef, TSlots> = 
    ((props: ComponentProps) => JSXElement) & {
        __setup: SetupFn;
        __name?: string;
        __props: TCombined;
        __ref: TRef;
        __slots: TSlots;
    };

LazyComponentFactory#

TSX
type LazyComponentFactory<T> = T & {
    preload: () => Promise<T>;
    isLoaded: () => boolean;
    __lazy: true;
};

SuspenseProps#

TSX
type SuspenseProps = {
    fallback?: JSXElement | (() => JSXElement);
};

PortalProps#

TSX
type PortalProps = 
    & Define.Prop<'to', string | Element>
    & Define.Prop<'disabled', boolean>;

ViewFn#

TSX
type ViewFn = () => JSXElement | JSXElement[] | undefined;

ComponentOptions#

TSX
interface ComponentOptions {
    name?: string;
}