CubeKit is a comprehensive collection of high-level React components designed specifically for Cube.dev applications. It provides ready-to-use components that help you build sophisticated analytics interfaces in minutes, not months.
npm install @cubekit/react
# or
yarn add @cubekit/react
Make sure you have the required peer dependencies installed:
npm install react@>=18.0.0 react-dom@>=18.0.0
Wrap your application with the CubeKitProvider to provide Cube.js context to all components:
import React from 'react';
import { CubeKitProvider } from '@cubekit/react';
const App = () => {
return (
<CubeKitProvider
config={{
cubeApiUrl: 'http://localhost:4000/cubejs-api/v1',
cubeApiToken: 'your-api-token', // Optional
pollInterval: 60000, // Optional: polling interval in ms
}}
>
<YourAppComponents />
</CubeKitProvider>
);
};
export default App;
The CubeKitConfig interface supports the following options:
interface CubeKitConfig {
cubeApiUrl: string; // Your Cube.js API URL
cubeApiToken?: string; // Optional API token for authentication
pollInterval?: number; // Optional polling interval in milliseconds
storageAdapter?: StorageAdapter; // Optional custom storage adapter
}
A powerful no-code interface that allows business users to build complex Cube.dev queries through an intuitive drag-and-drop interface.
import { QueryBuilder } from '@cubekit/react';
function MyApp() {
return (
<div className="p-4">
<QueryBuilder className="w-full h-screen" />
</div>
);
}
A dropdown component for selecting Cube.js cubes.
import { CubeSelect } from '@cubekit/react';
import { useCube } from '@cubekit/react';
function CubeSelector() {
const { meta } = useCube();
const [selectedCube, setSelectedCube] = useState<string | null>(null);
const handleCubeSelect = (cubeName: string) => {
setSelectedCube(cubeName);
console.log('Selected cube:', cubeName);
};
return (
<CubeSelect
cubes={meta?.cubes || []}
selectedCube={selectedCube}
onCubeSelect={handleCubeSelect}
validateJoins={(cubeName) => true} // Optional validation
/>
);
}
Prop | Type | Description |
---|---|---|
cubes |
CubeMetaItem[] |
Array of available cubes from meta |
selectedCube |
string | null |
Currently selected cube name (null if none) |
onCubeSelect |
(cubeName: string) => void |
Callback when cube selection changes |
validateJoins? |
(cubeName: string) => boolean |
Optional function to validate cube joins |
A generic multi-select dropdown component for selecting measures, dimensions, or segments.
import { MultiSelect } from '@cubekit/react';
import { MeasureIcon } from '@cubekit/react';
function MeasureSelector() {
const [selectedMeasures, setSelectedMeasures] = useState<string[]>([]);
const measures = [
{ name: 'Orders.count', title: 'Orders Count', type: 'count' },
{ name: 'Orders.totalAmount', title: 'Total Amount', type: 'sum' }
];
return (
<MultiSelect
items={measures}
selectedItems={selectedMeasures}
onSelectionChange={setSelectedMeasures}
getItemName={(item) => item.name}
getItemTitle={(item) => item.title}
getItemType={(item) => item.type}
getItemIcon={(item) => <MeasureIcon className="w-4 h-4" />}
placeholder="Select measures..."
emptyMessage="No measures available"
disabled={false}
/>
);
}
Prop | Type | Description |
---|---|---|
items |
T[] |
Array of items to select from (generic type) |
selectedItems |
string[] |
Currently selected item names |
onSelectionChange |
(items: string[]) => void |
Callback when selection changes |
getItemName |
(item: T) => string |
Function to get item's unique name/key |
getItemTitle |
(item: T) => string |
Function to get item's display title |
getItemIcon |
(item: T) => React.ReactNode |
Function to get item's icon |
placeholder |
string |
Placeholder text when no items selected |
emptyMessage |
string |
Message when no items available |
disabled? |
boolean |
Whether the component is disabled |
A comprehensive filter builder component for creating complex query filters.
import { FilterBuilder } from '@cubekit/react';
function QueryFilters() {
const [filterGroups, setFilterGroups] = useState([]);
return (
<FilterBuilder
availableDimensions={[
{ name: 'Orders.status', title: 'Order Status', type: 'string' },
{ name: 'Orders.createdAt', title: 'Created Date', type: 'time' }
]}
filterGroups={filterGroups}
onFiltersChange={setFilterGroups}
className="p-4"
/>
);
}
Component for configuring query options like limit, sorting, and row limits.
import { QueryOptions } from '@cubekit/react';
function QueryConfiguration() {
return (
<QueryOptions
limit={1000}
onLimitChange={(limit) => console.log('Limit:', limit)}
sortField="Orders.count"
sortDirection="desc"
onSortFieldChange={(field) => console.log('Sort field:', field)}
onSortDirectionChange={(direction) => console.log('Direction:', direction)}
className="mb-4"
/>
);
}
Action buttons for query operations (save, execute, export, etc.).
import { QueryActions } from '@cubekit/react';
function QueryControls() {
return (
<QueryActions
onExecute={() => console.log('Execute query')}
onSave={() => console.log('Save query')}
onExport={() => console.log('Export results')}
isExecuting={false}
className="flex gap-2"
/>
);
}
An AI-powered chat interface for natural language querying.
import { ConversationBuilder } from '@cubekit/react';
function AIQueryInterface() {
return (
<ConversationBuilder
className="w-full h-screen"
aiApiUrl="https://your-ai-api-endpoint"
enableVoiceInput={true}
/>
);
}
Individual message component within conversations.
import { Message } from '@cubekit/react';
function ChatMessage({ message }) {
return (
<Message
content={message.content}
type={message.type}
timestamp={message.timestamp}
isUser={message.isUser}
className="mb-4"
/>
);
}
Component for building and executing raw SQL queries.
import { SqlQueryBuilder } from '@cubekit/react';
function SqlInterface() {
return (
<SqlQueryBuilder
className="w-full h-screen"
defaultQuery="SELECT * FROM Orders LIMIT 100"
enableSyntaxHighlighting={true}
/>
);
}
SQL code editor component.
import { SqlEditor } from '@cubekit/react';
function QueryEditor() {
const [sql, setSql] = useState('SELECT * FROM Orders');
return (
<SqlEditor
value={sql}
onChange={setSql}
placeholder="Enter your SQL query..."
className="h-64 border rounded"
/>
);
}
Component for displaying SQL query results.
import { SqlQueryResult } from '@cubekit/react';
function ResultsDisplay({ results }) {
return (
<SqlQueryResult
results={results}
enableExport={true}
pageSize={50}
className="mt-4"
/>
);
}
Interactive visualization of your Cube.js schema with relationships.
import { SchemaVisualizer } from '@cubekit/react';
function SchemaExplorer() {
return (
<SchemaVisualizer
className="w-full h-screen"
onCubeSelect={(cubeName) => console.log('Selected cube:', cubeName)}
onMeasureSelect={(measure, cube) => console.log('Selected measure:', measure, 'from', cube)}
onDimensionSelect={(dimension, cube) => console.log('Selected dimension:', dimension, 'from', cube)}
showRelationships={true}
enableZoom={true}
/>
);
}
Individual cube node within the schema visualizer.
import { CubeNode } from '@cubekit/react';
function SchemaNode({ cube }) {
return (
<CubeNode
cube={cube}
position={{ x: 100, y: 100 }}
onSelect={(cubeName) => console.log('Selected:', cubeName)}
isSelected={false}
className="cursor-pointer"
/>
);
}
Drag-and-drop dashboard composition tool with a rich widget library and flexible layout management.
import { DashboardBuilder } from '@cubekit/react';
function Dashboard() {
return (
<DashboardBuilder
className="w-full h-screen"
enableEditing={true}
gridSize={12}
/>
);
}
Individual dashboard widget component.
import { Widget } from '@cubekit/react';
function DashboardWidget({ widgetConfig }) {
return (
<Widget
id={widgetConfig.id}
type={widgetConfig.type}
query={widgetConfig.query}
title={widgetConfig.title}
size={{ width: 6, height: 4 }}
onEdit={(id) => console.log('Edit widget:', id)}
onDelete={(id) => console.log('Delete widget:', id)}
className="border rounded-lg"
/>
);
}
Hook for accessing Cube.js context and functionality.
import { useCube } from '@cubekit/react';
function MyComponent() {
const {
meta,
isLoading,
error,
executeQuery,
executeSqlQuery,
refetchMeta
} = useCube();
// Use cube data and methods
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h3>Available Cubes: {meta?.cubes?.length}</h3>
<button onClick={refetchMeta}>Refresh Schema</button>
</div>
);
}
Return Value | Type | Description |
---|---|---|
meta |
CubeMeta | null |
Cube schema metadata |
cubes |
any[] | null |
Available cubes |
isLoading |
boolean |
Loading state |
error |
string | null |
Error message |
executeQuery |
(query: CubeQuery) => Promise<QueryResult> |
Execute Cube.js query |
executeSqlQuery |
(sql: string) => Promise<SqlQueryResult> |
Execute SQL query |
refetchMeta |
() => Promise<void> |
Refresh metadata |
cubeApi |
string |
API URL |
Hook for managing query builder state.
import { useQuery } from '@cubekit/react';
function QueryManager() {
const {
state,
updateQuery,
createQuery,
deleteQuery,
setCurrentResults
} = useQuery();
const handleCreateQuery = () => {
const queryId = createQuery('My New Query');
updateQuery(queryId, {
query: {
measures: ['Orders.count'],
dimensions: ['Orders.status'],
segments: [],
timeDimensions: [],
filters: [],
limit: 1000,
order: {}
}
});
};
return (
<div>
<button onClick={handleCreateQuery}>Create Query</button>
<p>Active queries: {state.savedQueries.length}</p>
</div>
);
}
Hook for managing conversation state in AI chat interface.
import { useConversation } from '@cubekit/react';
function ChatManager() {
const {
state,
sendMessage,
createConversation,
deleteConversation
} = useConversation();
const handleSendMessage = async (content: string) => {
await sendMessage(content, 'user');
// AI response would be handled internally
};
return (
<div>
<button onClick={() => createConversation('New Chat')}>
New Conversation
</button>
<p>Conversations: {state.conversations.length}</p>
</div>
);
}
Hook for managing dashboard state and widgets.
import { useDashboard } from '@cubekit/react';
function DashboardManager() {
const {
state,
createDashboard,
addWidget,
updateWidget,
deleteWidget
} = useDashboard();
const handleAddChart = () => {
if (state.activeDashboardId) {
addWidget(state.activeDashboardId, {
type: 'chart',
title: 'New Chart',
query: { measures: ['Orders.count'], dimensions: [] },
visualization: { type: 'bar' },
size: { width: 6, height: 4 },
position: { x: 0, y: 0 }
});
}
};
return (
<div>
<button onClick={handleAddChart}>Add Chart Widget</button>
<p>Dashboards: {state.dashboards.length}</p>
</div>
);
}
Hook for managing SQL query state.
import { useSqlQuery } from '@cubekit/react';
function SqlManager() {
const {
state,
executeQuery,
saveQuery,
updateQuery
} = useSqlQuery();
const handleExecuteQuery = async () => {
const sql = "SELECT * FROM Orders LIMIT 10";
await executeQuery(sql);
};
return (
<div>
<button onClick={handleExecuteQuery}>Execute Query</button>
<p>Query history: {state.queryHistory.length}</p>
</div>
);
}
import React from 'react';
import {
CubeKitProvider,
QueryBuilder,
QuerySidebar,
ChartVisualization,
QueryResultTable,
useCube,
useQuery
} from '@cubekit/react';
function App() {
return (
<CubeKitProvider config={{ cubeApiUrl: 'http://localhost:4000/cubejs-api/v1' }}>
<div className="flex h-screen">
<QuerySidebar className="w-64 border-r" />
<div className="flex-1 flex flex-col">
<QueryBuilder className="flex-1" />
</div>
</div>
</CubeKitProvider>
);
}
export default App;
import React from 'react';
import {
CubeKitProvider,
DashboardBuilder,
DashboardSidebar
} from '@cubekit/react';
function DashboardApp() {
return (
<CubeKitProvider config={{ cubeApiUrl: 'http://localhost:4000/cubejs-api/v1' }}>
<div className="flex h-screen">
<DashboardSidebar className="w-64 border-r" />
<DashboardBuilder className="flex-1" />
</div>
</CubeKitProvider>
);
}
export default DashboardApp;
import React from 'react';
import {
CubeKitProvider,
ConversationBuilder,
ConversationSidebar
} from '@cubekit/react';
function AIAnalyticsApp() {
return (
<CubeKitProvider config={{ cubeApiUrl: 'http://localhost:4000/cubejs-api/v1' }}>
<div className="flex h-screen">
<ConversationSidebar className="w-64 border-r" />
<ConversationBuilder
className="flex-1"
aiApiUrl="https://your-ai-api.com/chat"
enableVoiceInput={true}
/>
</div>
</CubeKitProvider>
);
}
export default AIAnalyticsApp;
CubeKit React is built with TypeScript and provides comprehensive type definitions:
import {
CubeQuery,
QueryResult,
CubeMeta,
CubeDimension,
CubeMeasure,
FilterOperator,
TimeGranularity
} from '@cubekit/react';
// All components and hooks are fully typed
const query: CubeQuery = {
measures: ['Orders.count'],
dimensions: ['Orders.status'],
timeDimensions: [],
filters: [{
member: 'Orders.status',
operator: 'equals',
values: ['completed']
}],
segments: [],
limit: 1000,
order: { 'Orders.count': 'desc' }
};
Customize how CubeKit stores data (queries, conversations, dashboards):
import { StorageAdapter, BrowserStorageAdapter } from '@cubekit/react';
// Use default browser storage
const defaultAdapter = new BrowserStorageAdapter();
// Or implement custom storage
class CustomStorageAdapter implements StorageAdapter {
async getItem(key: string): Promise<string | null> {
// Your custom storage logic
return localStorage.getItem(key);
}
async setItem(key: string, value: string): Promise<void> {
// Your custom storage logic
localStorage.setItem(key, value);
}
async removeItem(key: string): Promise<void> {
localStorage.removeItem(key);
}
}
// Use in provider
<CubeKitProvider
config={{
cubeApiUrl: 'your-api-url',
storageAdapter: new CustomStorageAdapter()
}}
>
<App />
</CubeKitProvider>
Build complex interfaces by composing smaller components:
function CustomQueryBuilder() {
return (
<div className="flex">
<QuerySidebar className="w-64" />
<div className="flex-1">
<QueryBuilder className="h-full" />
</div>
</div>
);
}
Always handle loading and error states:
function SafeQueryBuilder() {
const { isLoading, error } = useCube();
if (isLoading) return <div>Loading schema...</div>;
if (error) return <div>Error: {error}</div>;
return <QueryBuilder />;
}
Use React.memo for expensive components:
import React from 'react';
const OptimizedChart = React.memo(ChartVisualization);
Ensure components are accessible:
<QueryBuilder
className="focus:outline-none focus:ring-2 focus:ring-blue-500"
aria-label="Query Builder Interface"
/>