
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@contentstorage/react
Advanced tools
React hooks and components for @contentstorage - A key-value based CMS library with TypeScript support
React hooks and components for @contentstorage/core - A key-value based CMS library with TypeScript support.
npm install @contentstorage/react
or
yarn add @contentstorage/react
First, configure and pull content using the @contentstorage/core CLI:
# Pull content from ContentStorage
npx contentstorage pull --key YOUR_CONTENT_KEY
# Generate TypeScript types
npx contentstorage generate-types
import { ContentProvider } from '@contentstorage/react';
function App() {
return (
<ContentProvider
contentMode="headless"
contentKey="YOUR_CONTENT_KEY"
languageCodes={['EN', 'ET', 'FI']}
loadingFallback={<div>Loading content...</div>}
onError={(error) => console.error('Content error:', error)}
>
<YourApp />
</ContentProvider>
);
}
import { Text, useGetText, useManageLanguage } from '@contentstorage/react';
function Welcome() {
const greeting = useGetText({ contentId: 'home.greeting' });
const { currentLanguageCode, setLanguage } = useManageLanguage();
return (
<div>
<h1>{greeting}</h1>
{/* Or use the component */}
<Text contentId="home.description" />
<button onClick={() => setLanguage('ET')}>
Switch to Estonian
</button>
</div>
);
}
The main provider component that manages content state and language switching.
<ContentProvider
contentMode="headless"
contentKey="YOUR_CONTENT_KEY"
languageCodes={['EN', 'ET', 'FI']}
withPendingChanges={false} // Optional: include unpublished changes. Use true only in development mode
loadingFallback={<Spinner />} // Optional: loading UI
onError={(error) => handleError(error)} // Optional: error handler
>
{children}
</ContentProvider>
import enContent from './content/en.json';
import etContent from './content/et.json';
<ContentProvider
contentMode="static"
staticContent={{
EN: enContent,
ET: etContent,
}}
languageCodes={['EN', 'ET']}
>
{children}
</ContentProvider>
Get text content with type safety and optional variable substitution.
import { useGetText } from '@contentstorage/react';
function MyComponent() {
const title = useGetText({ contentId: 'home.title' });
// With variables
const greeting = useGetText({
contentId: 'home.welcome',
variables: { name: 'John' }
});
return <h1>{title}</h1>;
}
Get image content with URL and alt text.
import { useGetImage } from '@contentstorage/react';
function MyComponent() {
const { url, altText } = useGetImage({ contentId: 'home.hero' });
return <img src={url} alt={altText} />;
}
Get variation content (e.g., A/B test variants).
import { useGetVariation } from '@contentstorage/react';
function MyComponent() {
const content = useGetVariation({
contentId: 'home.cta',
variationId: 'variant-a'
});
return <div>{content}</div>;
}
Manage current language and switch between languages.
import { useManageLanguage } from '@contentstorage/react';
function LanguageSwitcher() {
const {
currentLanguageCode,
languageCodes,
setLanguage
} = useManageLanguage();
return (
<select
value={currentLanguageCode}
onChange={(e) => setLanguage(e.target.value)}
>
{languageCodes.map(lang => (
<option key={lang} value={lang}>{lang}</option>
))}
</select>
);
}
Get the current loading status of content.
import { useIsFetchingContent } from '@contentstorage/react';
function MyComponent() {
const { status } = useIsFetchingContent();
// status can be: 'idle' | 'loading' | 'failed'
if (status === 'loading') {
return <Spinner />;
}
return <Content />;
}
Access the full content context (used internally by other hooks).
import { useContent } from '@contentstorage/react';
function MyComponent() {
const {
languageCodes,
status,
currentLanguageCode,
setLanguage
} = useContent();
return <div>Current language: {currentLanguageCode}</div>;
}
Render text content as a string.
import { Text } from '@contentstorage/react';
function MyComponent() {
return (
<div>
<Text contentId="home.title" />
{/* With variables */}
<Text
contentId="home.greeting"
variables={{ name: 'John' }}
/>
</div>
);
}
Render an image with automatic URL and alt text.
import { Image } from '@contentstorage/react';
function MyComponent() {
return (
<Image
contentId="home.hero"
className="hero-image"
style={{ maxWidth: '100%' }}
/>
);
}
Render variation content.
import { Variation } from '@contentstorage/react';
function MyComponent() {
return (
<Variation
contentId="home.cta"
variationId="variant-a"
/>
);
}
When you use the contentstorage generate-types command from @contentstorage/core, type definitions are automatically generated. This enables full autocomplete and type checking:
// TypeScript will autocomplete content IDs and validate they exist
const title = useGetText({ contentId: 'home.title' }); // ✅ Valid
const invalid = useGetText({ contentId: 'invalid.key' }); // ❌ TypeScript error
// Variable types are also checked
const greeting = useGetText({
contentId: 'home.welcome',
variables: { name: 'John' } // ✅ TypeScript knows 'name' is required
});
Content is organized in a hierarchical key-value structure and accessed using dot notation:
{
"home": {
"title": "Welcome",
"greeting": "Hello, {name}!"
}
}
Access in your components:
<Text contentId="home.title" />
<Text contentId="home.greeting" variables={{ name: 'User' }} />
<Image contentId="home.hero" />
Add these convenient scripts to your package.json:
{
"scripts": {
"content:pull": "contentstorage pull --key YOUR_CONTENT_KEY",
"content:types": "contentstorage generate-types",
"content:sync": "npm run content:pull && npm run content:types"
}
}
Then run:
npm run content:sync
This package is a React wrapper around @contentstorage/core. You can also use core functions directly:
import { getText, getImage, fetchContent } from '@contentstorage/core';
// Direct API calls
const content = getText('home.title');
const image = getImage('home.hero');
// Programmatic content fetching
await fetchContent('ET', { contentKey: 'YOUR_KEY' });
See the core package documentation for more details on CLI commands, configuration, and API methods.
MIT
Kaido Hussar
For questions, issues, or feature requests, please open an issue on GitHub.
FAQs
React hooks and components for @contentstorage - A key-value based CMS library with TypeScript support
We found that @contentstorage/react demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.