SlotGhost
SlotGhost is a dashed placeholder for an empty slot, with an optional caption. Use it to show where windows can go in a custom window layout.
import { SlotGhost } from 'jarvis-react-ui';
Basic
SlotGhost is absolutely positioned at rect inside its nearest positioned ancestor; the rect is
applied through the CSS variables --lib-slot-ghost-x, -y, -w and -h. label adds a small
uppercase caption in the middle.
import { SlotGhost } from 'jarvis-react-ui';
export default function Basic() {
return (
<div className="relative h-[120px] w-[412px]">
<SlotGhost rect={{ x: 0, y: 0, w: 200, h: 120 }} label="Empty slot" />
<SlotGhost rect={{ x: 212, y: 0, w: 200, h: 120 }} />
</div>
);
}
Empty slots
Render a SlotGhost for every slot without a window, so the grid stays readable while it is partly
empty. Unlike the overlays, SlotGhost is positioned absolute, not fixed, and sits in the same
layer as your windows.
import { useEffect, useRef, useState } from 'react';
import { SLOT_IDS, SlotGhost, Window, computeSlot } from 'jarvis-react-ui';
import type { SlotId, SlotRect } from 'jarvis-react-ui';
const ASSIGNED: Partial<Record<SlotId, string>> = { L1: 'System', R2: 'Agenda', B2: 'Transcript' };
// The slot grid is made for a full viewport; to fit the demo frame it is computed at 2× and halved.
function demoSlot(id: SlotId, w: number, h: number): SlotRect {
const r = computeSlot(id, w * 2, h * 2);
return { x: r.x / 2, y: r.y / 2, w: r.w / 2, h: r.h / 2 };
}
export default function EmptySlots() {
const stageRef = useRef<HTMLDivElement>(null);
const [size, setSize] = useState({ w: 0, h: 0 });
useEffect(() => {
const stage = stageRef.current;
if (!stage) return;
const observer = new ResizeObserver(() =>
setSize({ w: stage.clientWidth, h: stage.clientHeight }),
);
observer.observe(stage);
return () => observer.disconnect();
}, []);
return (
<div ref={stageRef} className="relative h-[340px] w-full overflow-hidden">
{size.w > 0 &&
SLOT_IDS.map((id) => {
const rect = demoSlot(id, size.w, size.h);
const title = ASSIGNED[id];
return title === undefined ? (
<SlotGhost key={id} rect={rect} label={id} />
) : (
<Window
key={id}
id={id}
title={title}
position={rect}
draggable={false}
itemRenderer={() => id}
/>
);
})}
</div>
);
}
Note: Not part of WindowManager
WindowManager does not render SlotGhost; its empty slots stay blank. SlotGhost is a building block for layouts you assemble yourself from Window, useSlotDrag and the slot grid helpers.
Accessibility
SlotGhost is decorative: its root is aria-hidden, so the label is not announced, and it takes no
pointer events.
API
| Prop | Type | Default | Description |
|---|---|---|---|
rect (required) |
SlotRect |
Position and size in pixels, relative to the nearest positioned ancestor. | |
className |
string |
Extra classes for the root <div> element (the dashed placeholder). |
|
label |
string |
Small uppercase caption centred in the placeholder, e.g. the slot id. |
Type SlotRect
Rectangular geometry (pixel-absolute, viewport-relative).
| Field | Type | Default | Description |
|---|---|---|---|
h (required) |
number |
Height in px. | |
w (required) |
number |
Width in px. | |
x (required) |
number |
Left edge in px. | |
y (required) |
number |
Top edge in px. |