AbsoluteJS

React Islands

React hosts can use the loose Island primitive or a registry-bound createTypedIsland(registry) wrapper. Both lower to the same runtime.

#Authoring

Use a typed wrapper when you want framework, component, and prop inference from the registry. Keep the built-in Islandfor dynamic or ad hoc cases.

TSX
import { Island } from '@absolutejs/absolute/react';
import { TypedReactIsland } from '../../islands/registry';

export const IslandsPage = () => (
  <main>
    <h2>Typed Islands</h2>
    <TypedReactIsland
      framework="react"
      component="ReactCounter"
      hydrate="load"
      props={{ initialCount: 0, label: 'React island' }}
    />

    <h2>Loose Island</h2>
    <Island
      framework="vue"
      component="VueCounter"
      hydrate="visible"
      props={{ initialCount: 0, label: 'Loose deferred Vue island' }}
    />
  </main>
);

#Stores

React islands consume cross-framework state with useIslandStore. Import the same store module anywhere you want shared state.

TSX
import { useState } from 'react';
import { useIslandStore } from '@absolutejs/absolute/react';
import { counterIslandStore } from '../../islands/counterStore';

export const ReactCounter = ({
  initialCount,
  label
}: {
  initialCount: number;
  label: string;
}) => {
  const [count, setCount] = useState(initialCount);
  const sharedCount = useIslandStore(
    counterIslandStore,
    (state) => state.sharedCount
  );
  const incrementShared = useIslandStore(
    counterIslandStore,
    (state) => state.incrementShared
  );

  return (
    <div>
      <p>{label}</p>
      <strong>{'Local: ' + count}</strong>
      <strong>{'Shared: ' + sharedCount}</strong>
      <button onClick={() => setCount((value) => value + 1)}>
        Increment React
      </button>
      <button onClick={() => incrementShared()}>
        Increment Shared
      </button>
    </div>
  );
};