Files
2026-07-13 12:28:53 +08:00

118 lines
4.1 KiB
Plaintext

---
title: ImagePlaceholder
description: 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.
```tsx title="slides/q2-launch/index.tsx"
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](/docs/core-feature/assets-manager),
clicks the placeholder in the [inspector](/docs/core-feature/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
```ts
type ImagePlaceholderProps = {
/** Description of the content that belongs here. Becomes the alt text
* on the replaced <img>. Required. */
hint: string;
/** Box width in px. Omit to fill the parent. */
width?: number;
/** Box height in px. Omit to fill the parent. */
height?: number;
/** Extra inline styles, merged after the placeholder's own. */
style?: CSSProperties;
className?: string;
} & Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'style' | 'className'>;
```
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 `width` and `height` when 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%`.
```tsx
// 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:
1. Confirms the targeted JSX is an `<ImagePlaceholder>`.
2. Adds `import <ident> from './assets/<file>'` if the asset isn't already
imported.
3. Rewrites the element to:
```tsx
<img
src={<ident>}
alt="<hint>"
style={{ width, height, objectFit: 'cover', objectPosition: '50% 50%' }}
/>
```
The asset path must live under `./assets/` relative to the slide. 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 updates `objectPosition` (and, if you constrain the visible
region, `objectFit`) 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-intro deck (one screenshot per feature), an offsite
recap (team photo), a case study (customer logo).
Do **not** use it for decoration, generic stock-photo filler, or anywhere a
typographic or iconographic solution would do. Empty placeholders are friction
the user has to clear; only spend that friction when the alternative is worse.
See the **Image placeholders** section of the `slide-authoring` skill for the
full editorial checklist.