Reference
Assets, rich text, links, error handling, and the export reference for Localess in React Router.
Assets
resolveAsset(asset, params?)
Resolves a ContentAsset object to a fully qualified URL using the initialized client's origin. Pass an AssetTransformParams object as the second argument to request a resized image or a different output format — the params are appended as query string parameters that the Localess asset endpoint uses to transform the image on the fly. See Image Transforms for the full parameter reference.
import { resolveAsset } from "@localess/react";
const Image = ({ data }) => (
<img src={resolveAsset(data.image)} alt={data.imageAlt} />
);import { resolveAsset } from "@localess/react";
function HeroImage({ image, alt }: { image: ContentAsset; alt: string }) {
return (
<img
// Smaller, WebP thumbnail for a card
src={resolveAsset(image, { w: 400, f: 'webp' })}
alt={alt}
/>
);
}
function ProductImage({ image, alt }: { image: ContentAsset; alt: string }) {
return (
<img
// Fixed box crop + quality control
src={resolveAsset(image, { w: 800, h: 600, q: 70, f: 'avif' })}
alt={alt}
/>
);
}| Param | Type | Description |
|---|---|---|
w | number | Target width in pixels — whole number, 1–8192. Never upscales: a width above the source redirects to the source width |
h | number | Target height in pixels — same rules as w. Combined with w, the result is governed by fit |
fit | 'cover' | 'contain' | 'inside' | 'outside' | 'fill' | How the image fills the box when both w and h are set (default cover) |
q | number | Output quality, whole number 1–100. Defaults per format: JPEG and WebP 80, AVIF 50 |
f | 'webp' | 'jpeg' | 'png' | 'avif' | Converts the output format. Without it, the stored format is kept |
thumbnail | boolean | Extracts the first frame of an animated/video asset before resizing |
An out-of-range or fractional w, h or q throws a TypeError before the URL is built. For the untouched uploaded file, or to force a browser download, use the original and download links described below rather than a transform parameter.
Original file and download links
A bare resolveAsset(asset) URL is a rendition, not the uploaded file: still images are re-encoded at their format's default quality even with no parameters. When you need the exact bytes that were uploaded, or want the browser to save the file instead of displaying it, use the dedicated helpers:
import { resolveAssetDownload, resolveAssetOriginal } from '@localess/react';
<a href={resolveAssetOriginal(data.heroImage)}>View the original file</a>
<a href={resolveAssetDownload(data.brochure)} download>Download</a>Neither accepts transform parameters. A request that adds any is rejected with 400. Downloads keep non-ASCII file names intact.
Rich Text
Rich text renders from the field's Tiptap JSON straight to React elements — no Tiptap dependency, no dangerouslySetInnerHTML, and no browser APIs, so the same call works in a SPA, during SSR, and inside a React Server Component.
<LocalessRichText />
The component form, and the one to reach for by default.
import { LocalessRichText } from "@localess/react";
const Article = ({ data }) => (
<article>
<h1>{data.title}</h1>
<LocalessRichText content={data.body} />
</article>
);| Prop | Type | Description |
|---|---|---|
content | LocalessRichTextInput | The rich text field value. Accepts a full document, a single node, an array of nodes, or null/undefined, so a field value passes through without casting |
renderers | LocalessReactRichTextRenderers | Optional per-node/per-mark component overrides, keyed by element name |
renderRichText(content, options?)
The function form, for when you need the result as a value rather than as JSX — handing it to a layout component, wrapping it, or checking whether it produced anything.
import { renderRichText } from "@localess/react";
const body = renderRichText(data.body);Returns null for an empty or absent value, so an unfilled optional field renders nothing.
Supported elements
| Kind | Elements |
|---|---|
| Nodes | doc, paragraph, heading (levels 1–6), bulletList, orderedList, listItem, codeBlock, text |
| Marks | bold, italic, strike, underline, code, link |
An unknown node is skipped and an unknown mark renders its children unwrapped, each with a one-time console.warn outside production — so a document authored against a newer Localess release degrades instead of throwing.
Overriding a renderer
Pass renderers to replace the default output for one element. The key is the node or mark name, and the component receives that node's own fields plus children:
import { LocalessRichText } from "@localess/react";
import { sanitizeUrl } from "@localess/richtext";
import NextLink from "next/link";
const Link = ({ attrs, children }) => <NextLink href={sanitizeUrl(attrs.href)}>{children}</NextLink>;
<LocalessRichText content={data.body} renderers={{ link: Link }} />;The same map handles a custom heading that adds anchor links, or a codeBlock that runs a syntax highlighter. Anything you don't override keeps its default rendering.
A custom renderer receives the raw attributes — the built-in URL sanitising only runs on default rendering. Pass any URL you render yourself through
sanitizeUrlfrom@localess/richtext(a dependency of@localess/react), as above, so ajavascript:link can't reach the page.
Rendering is shared across every Localess SDK by
@localess/richtext, so one document renders identically in React, Angular, Vue, Svelte, and Astro.
Links
findLink(links, link)
Resolves a ContentLink field to a URL string. Use it to build href values from Localess content links.
import { findLink } from "@localess/react";
// type: 'content' → '/' + fullSlug, or '/not-found' if not in map
// type: 'url' → raw URI unchanged
const href = findLink(content.links, data.ctaLink);
const NavLink = ({ data, links }) => (
<a href={findLink(links, data.link)}>{data.label}</a>
);Error handling
getContentBySlug/getContentById throw LocalessApiError on a non-2xx API response — check error.status to distinguish a missing slug (404) from other failures:
import { getLocalessClient, LocalessApiError } from "@localess/react";
async function fetchPageData(slug: string) {
try {
return await getLocalessClient().getContentBySlug(slug);
} catch (error) {
if (error instanceof LocalessApiError && error.status === 404) {
return undefined;
}
throw error;
}
}Export Reference
The table below shows which symbols are available in each export.
| Symbol | @localess/react | @localess/react/ssr | @localess/react/vite |
|---|---|---|---|
localessInit | Yes | Yes | No — use the localess() plugin instead |
localess (Vite plugin) | No | No | Yes |
getLocalessClient | Yes | Yes | No — import from @localess/react |
localessClient (standalone client) | No | Yes | No |
isSyncConfigured / getOrigin | Yes | No | No |
LocalessApiError | Yes | Yes | No — import from @localess/react |
getComponent / getFallbackComponent | Yes | Yes | No |
resolveAsset | Yes | Yes | No — import from @localess/react |
resolveAssetOriginal / resolveAssetDownload | Yes | Yes | No — import from @localess/react |
LocalessComponent | Yes | No | No — import from @localess/react |
LocalessServerComponent / LocalessServerDocument | No | Yes | No |
LocalessServerComponentProps | No | Yes | No |
LocalessRichText / renderRichText | Yes | Yes | No — import from @localess/react |
findLink | Yes | Yes | No — import from @localess/react |
isServer | Yes | Yes | No |
| All content types | Yes | Yes | No |
LocalessDocument | Yes | No | No — import from @localess/react |
useLocaless | Yes | No | No — import from @localess/react |
localessEditable / localessEditableField | Yes | Yes | No — import from @localess/react |
isBrowser / isIframe | Yes | Yes | No |
isSyncEnabled / localessSyncOn / localessSyncOnChange / localessSyncReady | Yes | No | No |
Sync event types (LocalessSync, EventToApp, EventToAppOf, …) | Yes | Yes | No |
@localess/react/vite is narrowly scoped to the Vite plugin itself (localess() and its option types) — it doesn't re-export the runtime API. Import getLocalessClient, LocalessComponent, and everything else from the default @localess/react export, as shown in Setup above.
@localess/react/vite/virtual-modules is a separate, type-only subpath — ambient declarations for the virtual:localess-init/virtual:localess-components modules the plugin generates, needed only in tsconfig.json's types array (see Setup), never imported directly.