Widgets
The JavaScript SDK's widgets put CalmLens in your front end without building the interface yourself. The upload widget sends files from the browser and shows each file's progress and moderation decision, and the media component shows an asset from the CDN in a way that fits its moderation status. Both come in the same form for React, React Native, Vue, Svelte and plain HTML.
Choose your library
Install @calmlens/sdk and import the components for your UI library:
| Import | Components |
|---|---|
@calmlens/sdk/react | CalmLensUploader, CalmLensMedia and the useCalmLensUpload hook. Also works in Preact through preact/compat. |
@calmlens/sdk/react-native | CalmLensUploader, CalmLensMedia and the useCalmLensUpload hook, for React Native and Expo apps. They use React Native's own views, with no native modules to install. |
@calmlens/sdk/vue | CalmLensUploader, CalmLensMedia and the useCalmLensUpload composable, for Vue 3. |
@calmlens/sdk/svelte | CalmLensUploader and CalmLensMedia, for Svelte 5. |
@calmlens/sdk/elements | The <calmlens-uploader> and <calmlens-media> custom elements, for plain HTML, Angular, Solid, Lit and any library that renders custom elements. |
Importing @calmlens/sdk/elements defines both elements. The components share one core, @calmlens/sdk/ui, which you can use to build your own interface on the same upload queue. The file-type icons the upload widget draws for files without a preview are in @calmlens/sdk/file-icons, for showing files the same way elsewhere in your app.
Style and translate
The React components render their small stylesheet with them: React places it in the page's head once, including when you render on the server, so media keeps its layout before your scripts load. With Vue, Svelte or the web components, import @calmlens/sdk/styles.css once in your app, or link it from your page's head. Change the colours and corners with CSS custom properties such as --calmlens-accent and --calmlens-radius; your values take precedence on any element. To style the calmlens-* classes yourself, pass unstyled to the React components, or leave out the stylesheet import.
The React Native components take a theme instead, with accent, text, radius and the status colours; anything you leave out keeps its default. The secondary text, border and surface colours are mixed from text, so a dark screen usually needs only text and accent.
All text can be replaced through messages, keyed by message name (dropzoneTitle, uploading, reveal) or by error code, which also translates the components.
Test without a network
MockCalmLensAppClient from @calmlens/sdk/testing stands in for the uploader's client. It applies upload preset rules, such as a required token and size limits, with the API's error codes, and stores uploads in a MockCalmLensServerClient, whose CDN serves them with the same moderation rules:
import { CalmLensUploader } from "@calmlens/sdk/react";
import { MockCalmLensAppClient } from "@calmlens/sdk/testing";
<CalmLensUploader
uploadPresetId="test-preset"
createClient={(options) =>
new MockCalmLensAppClient({
...options,
mockOptions: { queuedOutcome: "blocked", preset: { maxFileSizeInBytes: 5_000_000 } },
})
}
/>;The widget playground runs every component in each library against these mocks, so you can try uploads, decisions and age-restricted media without a project.