Framework Integration
Cognivo components are Web Components — they work in any framework or vanilla HTML. First-class React and Vue adapters provide native DX with full TypeScript support.
Vanilla HTML / Any Framework
Import once, use everywhere. No framework adapter needed.
<script type="module"> import '@cognivo/components'; </script> <link rel="stylesheet" href="node_modules/@cognivo/tokens/dist/index.css"> <cg-button variant="primary" size="md">Click me</cg-button> <ai-chat placeholder="Ask anything..."></ai-chat> <ai-thinking variant="dots" text="Analyzing..."></ai-thinking>Web Components work natively in Angular, Svelte, Astro, SolidJS, and any framework that renders to the DOM. No wrappers required.
React
Type-safe React wrappers with proper event handling and prop mapping.
Installation
pnpm add @cognivo/adapter-react @cognivo/components @cognivo/tokens Setup
// app.tsx or layout.tsx — import tokens CSS once
import '@cognivo/tokens/dist/index.css'; Usage
import { CgButton, CgInput, CgCard, AiChat, AiThinking } from '@cognivo/adapter-react';
function Dashboard() {
const [query, setQuery] = useState('');
return (
<div>
<CgCard variant="elevated">
<CgInput
label="Search"
value={query}
onCgInput={(e) => setQuery(e.detail.value)}
/>
<CgButton variant="primary" onCgClick={() => search(query)}>
Search
</CgButton>
</CgCard>
<AiThinking variant="dots" text="Processing..." />
<AiChat placeholder="Ask a question..." />
</div>
);
} Event Handling
React wrappers map Web Component custom events to React-style callbacks.
The event prefix is on + PascalCase event name.
| Web Component Event | React Prop | Detail Type |
|---|---|---|
cg-click | onCgClick | MouseEvent |
cg-input | onCgInput | { value: string } |
cg-change | onCgChange | { value: string, error?: boolean } |
ai-message | onAiMessage | { text: string, role: string } |
TypeScript
// All props and events are fully typed
import type { CgButton, CgInput, AiChat } from '@cognivo/adapter-react';
// Example: typed event handler
const handleInput = (e: CustomEvent<{ value: string }>) => {
console.log(e.detail.value);
};
Vue
Vue 3 wrappers with v-model support and typed props.
Installation
pnpm add @cognivo/adapter-vue @cognivo/components @cognivo/tokens Setup
// main.ts
import '@cognivo/tokens/dist/index.css'; Usage
<script setup lang="ts"> import { CgButton, CgInput, CgCard, AiChat } from '@cognivo/adapter-vue'; import { ref } from 'vue'; const query = ref(''); </script> <template> <CgCard variant="elevated"> <CgInput label="Search" :value="query" @cg-input="query = $event.detail.value" /> <CgButton variant="primary" @cg-click="search(query)"> Search </CgButton> </CgCard> <AiChat placeholder="Ask a question..." /> </template>Event Handling
Vue wrappers emit the same custom events as the Web Components. Use
@event-namesyntax.
Svelte, Angular, SolidJS
No adapter needed — use Web Components directly.
Svelte
<script> import '@cognivo/components'; import '@cognivo/tokens/dist/index.css'; </script> <cg-button variant="primary" on:cg-click={handleClick}> Click me </cg-button>Angular
// app.module.ts — enable custom elements import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class AppModule {} // Import in styles.css @import '@cognivo/tokens'; // Use in templates // <cg-button variant="primary">Click</cg-button>
Dark Mode (All Frameworks)
// Set on document root — works in all frameworks
document.documentElement.setAttribute('data-theme', 'dark');
// React example
function ThemeToggle() {
const [dark, setDark] = useState(true);
useEffect(() => {
document.documentElement.setAttribute(
'data-theme', dark ? 'dark' : 'light'
);
}, [dark]);
return <CgSwitch checked={dark} onCgChange={() => setDark(!dark)} />;
} Tree Shaking
Import individual components to reduce bundle size:
// Full library (registers all 182 components)
import '@cognivo/components';
// Individual imports (tree-shakeable)
import { CgButton } from '@cognivo/components';
import { AiChat } from '@cognivo/components'; Server-Side Rendering
Cognivo components SSR cleanly via @lit-labs/ssr. The @cognivo/ssr
package provides ergonomic helpers that render Lit templates to a string with Declarative
Shadow DOM, so the markup is visible on first paint before hydration.
Installation
pnpm add @cognivo/ssr @cognivo/components lit Core Usage
import { renderToString, html } from '@cognivo/ssr';
import '@cognivo/components';
const markup = renderToString(html`
<cg-card>
<cg-button variant="primary">Click me</cg-button>
</cg-card>
`); Next.js (App Router)
Render on the server, then import the client bundle to upgrade the custom elements after hydration.
// app/page.tsx — Server Component
import { renderToString, html } from '@cognivo/ssr';
import '@cognivo/components'; // registers element classes for SSR
export default function Page() {
const markup = renderToString(html`
<cg-card>
<cg-button variant="primary">Get started</cg-button>
</cg-card>
`);
return <div dangerouslySetInnerHTML={{ __html: markup }} />;
} // app/cognivo-client.tsx — Client Component
'use client';
import { useEffect } from 'react';
export function CognivoClient() {
useEffect(() => {
// Upgrades the custom elements in the SSR'd markup
import('@cognivo/components');
}, []);
return null;
} Astro
Use set:html with the rendered markup, then ship a client script that registers
the elements for hydration.
--- import { renderToString, html } from '@cognivo/ssr'; import '@cognivo/components'; const markup = renderToString(html` <cg-card> <cg-button variant="primary">Click me</cg-button> </cg-card> `); --- <div set:html={markup}></div> <script> import '@cognivo/components'; </script>Remix
The same pattern works in Remix: call
renderToStringinside your loader or route module, emit the HTML in the response, and import@cognivo/componentsin the client entry to upgrade the elements after hydration.Caveat: Declarative Shadow DOM is supported natively in Chromium 111+, Safari 16.4+, and Firefox 123+. For older browsers, ship the@webcomponents/template-shadowrootpolyfill alongside the client bundle.