ImagePlaceholder
A typed stand-in for a real image the user has to supply.
ImagePlaceholder is a small runtime component that renders a sized, dashed
box with a hint label. Drop it into a slide whenever the layout calls for a
real image — a product screenshot, a team photo, a customer dashboard — that
you don't have on disk yet.
import { ImagePlaceholder } from '@open-slide/core';
const Hero = () => (
<ImagePlaceholder hint="Product hero screenshot" width={1280} height={720} />
);
export default [Hero];The user uploads the real file via the Assets panel,
clicks the placeholder in the inspector, and picks
Replace… — the JSX is rewritten to a real <img> and the asset import is
added at the top of the file. The replacement keeps the placeholder's width
and height so the image lands in exactly the same slot.
Props
Prop
Type
Any other <div> attribute is passed through too (except children, style,
and className, which the component owns).
When both width and height are set, the placeholder renders the dimensions
under the hint so you can eyeball aspect ratios while drafting.
Sizing
Pick one of two modes:
- Fixed box — pass
widthandheightwhen the layout has a hard image slot (a hero card, a logo lockup at a known size). - Fill the parent — omit both when the placeholder sits inside a flex or
grid cell that already controls its size. The component defaults to
width: 100%; height: 100%.
// Fixed
<ImagePlaceholder hint="Q3 revenue chart" width={960} height={540} />
// Fill a flex/grid cell
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 32 }}>
<ImagePlaceholder hint="Before — old dashboard" />
<ImagePlaceholder hint="After — new dashboard" />
</div>The hint should describe the content the user has to supply
("Q3 revenue chart"), not its layout role ("hero image").
Replacement workflow
The inspector's Replace… action is wired to a Vite-plugin op called
replace-placeholder-with-image. Given an asset path, it:
-
Confirms the targeted JSX is an
<ImagePlaceholder>. -
Adds
import <ident> from './assets/<file>'if the asset isn't already imported. -
Rewrites the element to:
<img src={<ident>} alt="<hint>" style={{ width, height, objectFit: 'cover', objectPosition: '50% 50%' }} />
The asset path must start with ./assets/ (slide-local) or @assets/
(global). If you skip the inspector and want to swap the placeholder by
hand, the snippet above is exactly what to write.
Cropping
After replacement the image is a regular <img> with objectFit: 'cover',
which means the asset's aspect ratio rarely matches the slot exactly. To
reframe the visible region:
- Double-click the image while the inspector is active, or
- Click it once and choose Crop in the property panel.
The crop dialog writes objectFit (Fill = cover, Fit = contain) and
stores the crop rectangle as an objectViewBox: inset(…) value on the same
inline style block — no asset is mutated, so you can reopen the dialog
later and adjust.
When to use it
Use a placeholder only when a specific concrete image is required by the deck's topic — a product screenshot, a team photo, a customer logo. Don't use it for decoration or generic stock-photo filler; if a typographic or iconographic solution would do, prefer that.