You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@getforma/core

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@getforma/core

Real DOM reactive library — fine-grained signals, islands architecture, SSR hydration. No virtual DOM, no diffing. ~15KB gzipped.

Source
npmnpm
Version
0.3.0
Version published
Weekly downloads
119
-92.96%
Maintainers
1
Weekly downloads
 
Created
Source

FormaJS

CI npm License: MIT

Reactive DOM library with fine-grained signals. No virtual DOM — h() creates real elements, signals update only what changed. ~15KB gzipped.

Install

npm install @getforma/core

Or use the CDN (no build step required):

<script src="https://unpkg.com/@getforma/core/dist/formajs-runtime.global.js"></script>

Why FormaJS?

Most UI libraries make you choose: simple but limited (Alpine, htmx), or powerful but complex (React, Vue, Svelte). FormaJS gives you a single reactive core that scales from a CDN script tag to a full-stack Rust SSR pipeline.

Design principles:

  • Real DOM, not virtual DOM. h('div') returns an actual HTMLDivElement. Signals mutate it directly. No diffing pass, no reconciliation overhead for simple updates. Inspired by Solid.
  • Fine-grained reactivity. Powered by alien-signals. When a signal changes, only the specific DOM text node or attribute that depends on it updates — not the whole component tree.
  • Three entry points, one engine. HTML Runtime (like Alpine — zero build step), h() hyperscript (like Preact), or JSX. All share the same signal graph. Pick the right tool for the job, upgrade without rewriting.
  • CSP-safe by default. The HTML Runtime includes a hand-written expression parser. new Function() is an opt-in fallback, not a requirement. Ship to strict CSP environments without worry.
  • Islands over SPAs. activateIslands() hydrates independent regions of server-rendered HTML. Each island is self-contained. Ship less JavaScript, keep server-rendered content instant.

What FormaJS is not: It's not a framework with opinions about routing, data fetching, or state management patterns. It's a reactive DOM library. You bring the architecture.

Three Ways to Use FormaJS

1. HTML Runtime (no build step)

Drop a script tag, write data-* attributes. Zero config, zero tooling.

<script src="https://unpkg.com/@getforma/core/dist/formajs-runtime.global.js"></script>

<div data-forma-state='{"count": 0}'>
  <p data-text="{count}"></p>
  <button data-on:click="{count++}">+1</button>
  <button data-on:click="{count = 0}">Reset</button>
</div>

Supported Directives

DirectiveDescriptionExample
data-forma-stateDeclare reactive state (JSON)data-forma-state='{"count": 0}'
data-textBind text contentdata-text="{count}"
data-showToggle visibility (display)data-show="{isOpen}"
data-ifConditional render (add/remove from DOM)data-if="{loggedIn}"
data-modelTwo-way binding (inputs)data-model="{email}"
data-on:eventEvent handlerdata-on:click="{count++}"
data-class:nameConditional CSS classdata-class:active="{isActive}"
data-bind:attrDynamic attributedata-bind:href="{url}"
data-listList rendering with keyed reconciliationdata-list="{items}"
data-computedComputed valuedata-computed="doubled = count * 2"
data-persistPersist state to localStoragedata-persist="{count}"
data-fetchFetch data from URLdata-fetch="GET /api/items → items"
data-transition:*Enter/leave CSS transitionsdata-transition:enter="fade-in"

CSP-safe expression parser — no eval() or new Function() by default. For strict CSP environments, use the hardened build:

<script src="https://unpkg.com/@getforma/core/dist/formajs-runtime-hardened.global.js"></script>

2. Hyperscript — h()

npm install @getforma/core
import { createSignal, h, mount } from '@getforma/core';

const [count, setCount] = createSignal(0);

mount(() =>
  h('button', { onClick: () => setCount(count() + 1) },
    () => `Clicked ${count()} times`
  ),
  '#app'
);

3. JSX

Same h() function, JSX syntax. Configure your bundler:

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}
import { createSignal, h, Fragment, mount } from '@getforma/core';

const [count, setCount] = createSignal(0);

function Counter() {
  return (
    <>
      <p>{() => `Count: ${count()}`}</p>
      <button onClick={() => setCount(count() + 1)}>+1</button>
    </>
  );
}

mount(() => <Counter />, '#app');

If you use @getforma/build, JSX is preconfigured — just write .tsx files.

Core API

Signals

import { createSignal, createEffect, createComputed, batch } from '@getforma/core';

const [count, setCount] = createSignal(0);
const doubled = createComputed(() => count() * 2);

createEffect(() => console.log('count:', count()));

batch(() => {
  setCount(1);
  setCount(2); // effect fires once with value 2
});

Conditional Rendering

import { createSignal, createShow, createSwitch, h } from '@getforma/core';

const [loggedIn, setLoggedIn] = createSignal(false);

// createShow — toggle between two branches
createShow(loggedIn,
  () => h('p', null, 'Welcome back'),
  () => h('p', null, 'Please sign in'),
);

// createSwitch — multi-branch with caching
const [view, setView] = createSignal('home');
createSwitch(view, [
  { match: 'home', render: () => h('div', null, 'Home') },
  { match: 'settings', render: () => h('div', null, 'Settings') },
], () => h('div', null, '404 Not Found'));

List Rendering

import { createSignal, createList, h } from '@getforma/core';

const [items, setItems] = createSignal([
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
]);

createList(
  items,
  (item) => item.id,  // key function
  (item) => h('li', null, item.name),
);

Store (deep reactivity)

import { createStore } from '@getforma/core';

const [state, setState] = createStore({
  user: { name: 'Alice', prefs: { theme: 'dark' } },
  items: [1, 2, 3],
});

// Read reactively
state.user.name;        // 'Alice'

// Mutate — only affected subscribers update
setState('user', 'name', 'Bob');
setState('items', items => [...items, 4]);

Components

import { defineComponent, onMount, onUnmount, h } from '@getforma/core';

const Timer = defineComponent(() => {
  const [seconds, setSeconds] = createSignal(0);

  onMount(() => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(id); // cleanup on unmount
  });

  return h('span', null, () => `${seconds()}s`);
});

document.body.appendChild(Timer());

Context (Dependency Injection)

import { createContext, provide, inject } from '@getforma/core';

const ThemeCtx = createContext('light');

provide(ThemeCtx, 'dark');
const theme = inject(ThemeCtx); // 'dark'

Islands Architecture

For server-rendered HTML, activate independent interactive regions:

import { activateIslands, createSignal, h } from '@getforma/core';

activateIslands({
  Counter: (el, props) => {
    const [count, setCount] = createSignal(props.initial ?? 0);
    // Hydrate: attach reactivity to existing server-rendered DOM
  },
});
<!-- Server-rendered HTML -->
<div data-forma-island="Counter" data-forma-props='{"initial": 5}'>
  <span>5</span>
  <button>+1</button>
</div>

Subpath Exports

ImportDescription
@getforma/coreSignals, h(), mount(), lists, stores, components
@getforma/core/runtimeHTML Runtime — initRuntime(), mount(), unmount()
@getforma/core/runtime-hardenedRuntime with new Function() locked off (strict CSP)
@getforma/core/ssrServer-side rendering — renderToString(), renderToStream()
@getforma/core/tc39TC39-compatible Signal.State and Signal.Computed classes

Examples

See the examples/ directory:

  • counter — minimal h() counter
  • counter-jsx — same counter with JSX syntax
  • todo — todo list with createList and keyed reconciliation
  • data-table — sortable table with createList

Ecosystem

PackageDescription
@getforma/coreThis library — npm install @getforma/core
@getforma/compilerSSR compiler — .tsx to FMIR binary
@getforma/buildesbuild wrapper with JSX + SSR preconfigured
create-forma-appnpx @getforma/create-app project scaffolder
formaRust server framework (forma-ir + forma-server)

License

MIT

Keywords

signals

FAQs

Package last updated on 14 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts