@tgimg/react
v0.1.3
Published
Ultra-fast image component for Telegram Mini Apps — instant thumbhash placeholders, adaptive format/size selection, zero layout shift
Downloads
282
Maintainers
Readme
@tgimg/react
Ultra-fast image component for Telegram Mini Apps and webviews. Renders thumbhash placeholders instantly, then swaps to the optimal format and size (AVIF → WebP → JPEG) with zero layout shift.
Part of the tgimg pipeline: use the CLI to build assets and a manifest, then feed the manifest to this runtime.
Install
npm install @tgimg/react
# or
pnpm add @tgimg/react
yarn add @tgimg/reactPeer dependencies: React 18+, React DOM 18+.
Quick start
Build images with the tgimg CLI (outputs a manifest + optimized files):
tgimg build ./images --out ./public/tgimg --profile telegram-webviewProvide the manifest to your app and use
<TgImg />:import { TgImgProvider, TgImg } from '@tgimg/react'; import manifest from './public/tgimg/tgimg.manifest.json'; // or virtual:tgimg-manifest with vite-plugin-tgimg function App() { return ( <TgImgProvider manifest={manifest}> <TgImg src="hero/banner" alt="Hero" width={640} /> <TgImg src="cards/item" alt="Item" width={320} fit="cover" radius={8} /> </TgImgProvider> ); }
src is the asset key from the manifest (e.g. the path without extension you used when building). The component picks the best variant (format + size), shows a thumbhash placeholder immediately, then swaps to the real image with no layout shift.
API
<TgImgProvider manifest>
Wraps the tree and provides the tgimg manifest so every <TgImg /> can resolve src to variants.
| Prop | Type | Description |
|-----------|------------------|--------------------------------|
| manifest| TgImgManifest | Manifest from tgimg build. |
| children| ReactNode | Your app (e.g. <TgImg />). |
<TgImg />
Renders an image for a manifest asset: placeholder first, then the selected variant.
| Prop | Type | Default | Description |
|-------------------|-------------------------|------------|-------------|
| src | string | required | Asset key in the manifest (e.g. "promo/banner"). |
| alt | string | required | Alt text for accessibility. |
| width | number | — | Width in CSS pixels. Omit to fill container. |
| height | number | — | Height in CSS pixels. Omit to use aspect ratio from manifest. |
| ratio | number | from manifest | Aspect ratio override (width/height). |
| fit | 'cover' \| 'contain' \| 'fill' \| 'none' | 'cover' | Object-fit. |
| radius | number \| string | — | Border radius (px or CSS value). |
| priority | boolean | false | If true, load eagerly (no lazy). |
| transition | 'auto' \| 'instant' \| 'reveal' \| 'off' | 'auto' | How to swap placeholder → image. |
| placeholderChroma | number | auto | Thumbhash color (0 = gray, 1 = full). |
| baseUrl | string | manifest base_path | URL prefix for asset paths. |
| className | string | — | Extra class on the wrapper. |
| style | React.CSSProperties | — | Inline styles on the wrapper. |
| onLoad | () => void | — | Called when the image has loaded and decoded. |
| onError | (error: Error) => void| — | Called on load error. |
You can also pass manifest directly to <TgImg manifest={...} /> instead of using TgImgProvider.
Hooks
useManifest()— Returns the manifest from the nearestTgImgProvider. Throws if missing.useAsset(src: string)— Returns the asset entry forsrcfrom the manifest, ornull.useTgImg(props)— Low-level hook that returns resolved URLs and state; used internally by<TgImg />.
Utilities
selectVariant(asset, width, dpr, formats)— Picks the best variant for given width, DPR, and format support.buildSrcSet(asset, width, formats)— Builds asrcsetstring for the asset.detectFormats()/getFormatsSync()— Detect supported formats (AVIF, WebP, etc.) in the environment.thumbHashToDataURL(base64)— Decode thumbhash base64 to a data URL for the placeholder image.
See the package exports for full types (TgImgManifest, TgImgAsset, TgImgProps, etc.).
Examples
Priority image (above the fold):
<TgImg src="hero/banner" alt="Hero" width={1280} priority />Lazy card with cover fit and radius:
<TgImg src="cards/product" alt="Product" width={320} height={240} fit="cover" radius={12} />With Vite and virtual manifest (vite-plugin-tgimg):
// vite.config.ts
import tgimg from 'vite-plugin-tgimg';
// ...
plugins: [tgimg({ dir: 'public/tgimg' })],import manifest from 'virtual:tgimg-manifest';
import { TgImgProvider, TgImg } from '@tgimg/react';
<TgImgProvider manifest={manifest}>
<TgImg src="promo/banner" alt="Promo" width={640} />
</TgImgProvider>Use cases
- Telegram Mini Apps — Small placeholders, format fallbacks for iOS/Android webviews, no blink.
- SPAs and static sites — One
tgimg build, serve from CDN; content-addressed filenames for caching. - Zero CLS — Aspect ratio and size come from the manifest; no layout jump when the image loads.
Requirements
- Assets and manifest must be produced by tgimg CLI (
tgimg build). - Manifest version must be supported by this package (see
MANIFEST_VERSION_MIN/MANIFEST_VERSION_MAX).
License
MIT · tgimg-core
