Img — Sample

A runnable gallery using the built-in <Img> component: an eager hero banner, a blurred placeholder, and lazily-loaded photos.

Sample

Server component

A page that mixes an eager above-the-fold hero with a grid of lazily-loaded photos and one blurred placeholder. None of this needs a "use client" directive —<Img> handles hydration internally.

app/pages/gallery.tsxtypescript
import { Img } from 'nukejs'

const photos = [
    { src: '/photos/lake.jpg',        alt: 'Still lake at dusk' },
    { src: '/photos/forest.jpg',      alt: 'Pine forest in fog' },
    { src: '/photos/desert.jpg',      alt: 'Dunes at golden hour' },
    { src: '/photos/city.jpg',        alt: 'City skyline at night' },
]

export default function Gallery() {
    return (
        <main>
            {/* Above-the-fold: load immediately */}
            <Img
                src="/photos/hero.jpg"
                alt="Welcome to the gallery"
                width={1600}
                height={600}
                eager
                className="hero"
            />

            <h1>Gallery</h1>

            <div className="grid">
                {photos.map(p => (
                    <Img
                        key={p.src}
                        src={p.src}
                        alt={p.alt}
                        width={400}
                        height={300}
                        placeholder={`${p.src.replace('.jpg', '')}-tiny.jpg`}
                    />
                ))}
            </div>
        </main>
    )
}

Default export only

As with every page, this file exports a single default component. The component can beasync and fetch the photo list from a database — <Img> works exactly the same in an async server component:

app/pages/gallery.tsxtypescript
import { Img } from 'nukejs'

export default async function Gallery() {
    const photos = await db.photos.findMany()

    return (
        <div className="grid">
            {photos.map(p => (
                <Img key={p.id} src={p.url} alt={p.alt} width={400} height={300} />
            ))}
        </div>
    )
}

Styling notes

Pass className and style like a normal <img>. The internal blur transition is merged with your inline style, so don't setfilter or opacity directly unless you want to override the placeholder fade.

app/public/gallery.csstypescript
.hero { object-fit: cover; border-radius: 12px; }

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
}

.grid img { width: 100%; height: auto; border-radius: 8px; }
💡
Always set width & height Providing both reserves space in the document immediately, so lazy-loaded images never cause layout shift when they swap in.