Documentation Index
Fetch the complete documentation index at: https://docs-staging.skybridge.tech/llms.txt
Use this file to discover all available pages before exploring further.
The createStore function creates a Zustand store that automatically syncs with the view’s persistent state. Unlike useViewState, this provides a full Zustand store with actions and middleware support, making it ideal for complex state management scenarios.
Basic usage
import { createStore } from "skybridge/web";
import type { StateCreator } from "zustand";
type CounterState = {
count: number;
increment: () => void;
decrement: () => void;
};
const useCounterStore = createStore<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
function CounterView() {
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
Parameters
storeCreator
storeCreator: StateCreator<State, [], [], State>;
A Zustand state creator function that defines your store’s initial state and actions. This follows the standard Zustand pattern.
defaultState
defaultState?: State | (() => State)
Optional default state to use if no persisted state exists. Can be:
- A value of type
State
- A function that returns
State (lazy initialization)
If window.openai.widgetState exists, it will take precedence over defaultState.
Returns
UseBoundStore<StoreApi<State>>;
A Zustand store that can be used with the standard Zustand hooks:
store.getState() - Get the current state
store.setState() - Update the state
store.subscribe() - Subscribe to state changes
useStore(selector) - React hook to access the store
Features
Automatic State Persistence
State changes are automatically persisted to window.openai.setWidgetState. The state is serialized (functions are stripped) before persistence.
State Initialization Priority
The store initializes state in the following order:
window.openai.widgetState (if available) - highest priority
defaultState parameter (if provided)
- State returned by
storeCreator
Examples
Todo List with Actions
import { createStore } from "skybridge/web";
import type { StateCreator } from "zustand";
type Todo = {
id: string;
text: string;
completed: boolean;
};
type TodoState = {
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: string) => void;
removeTodo: (id: string) => void;
clearCompleted: () => void;
};
const useTodoStore = createStore<TodoState>((set) => ({
todos: [],
addTodo: (text) =>
set((state) => ({
todos: [
...state.todos,
{ id: crypto.randomUUID(), text, completed: false },
],
})),
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: (id) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
clearCompleted: () =>
set((state) => ({
todos: state.todos.filter((todo) => !todo.completed),
})),
}));
function TodoView() {
const todos = useTodoStore((state) => state.todos);
const addTodo = useTodoStore((state) => state.addTodo);
const toggleTodo = useTodoStore((state) => state.toggleTodo);
const removeTodo = useTodoStore((state) => state.removeTodo);
const clearCompleted = useTodoStore((state) => state.clearCompleted);
const [input, setInput] = useState("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input.trim()) {
addTodo(input.trim());
setInput("");
}
};
return (
<div className="todo-view">
<h3>Todo List</h3>
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a todo..."
/>
<button type="submit">Add</button>
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span
style={{
textDecoration: todo.completed ? "line-through" : "none",
}}
>
{todo.text}
</span>
<button onClick={() => removeTodo(todo.id)}>Remove</button>
</li>
))}
</ul>
<button onClick={clearCompleted}>Clear Completed</button>
</div>
);
}
Comparison with useViewState
| Feature | createStore | useViewState |
|---|
| Type | Zustand store | React hook |
| Use Case | Complex state with actions | Simple state updates |
| Actions | Supported | Not supported |
| Middleware | Can be composed | Not supported |
| Selectors | Full Zustand selectors | Returns full state |
| Performance | Fine-grained subscriptions | Re-renders on any change |
| API | Zustand API | React useState-like API |
Use createStore when you need:
- Actions and methods on your state
- Complex state logic
- Fine-grained subscriptions
- Zustand middleware support
Use useViewState when you need:
- Simple state management
- React
useState-like API
- Quick setup without Zustand knowledge