Need UI components? For buttons, inputs, layouts, and charts, see the Extension Kit Components guide.
All imports come from @teachfloor/extension-kit, which is automatically installed when you create an app.
Signaling App Ready
Basic Usage
Signal to the platform that your app is ready:
Code
import { initialize } from '@teachfloor/extension-kit'function App() { useEffect(() => { initialize() // Signal app is ready }, []) return <div>My App</div>}
With Context Provider
Code
import { ExtensionContextProvider } from '@teachfloor/extension-kit'// The provider signals readiness automatically<ExtensionContextProvider autoInit={true}> <App /></ExtensionContextProvider>
API Reference
Events
Subscribe to Events
Listen to platform events using subscribeToEvent(). Events receive two parameters: the event data and an objectContext containing contextual information based on your app's permissions.
Code
import { subscribeToEvent } from '@teachfloor/extension-kit'// Viewport changes - objectContext includes course/module/element based on permissionssubscribeToEvent('environment.viewport.changed', (viewport, objectContext) => { console.log('User navigated to:', viewport) if (objectContext.course) { console.log('Course:', objectContext.course.name) } if (objectContext.module) { console.log('Module:', objectContext.module.name) } if (objectContext.element) { console.log('Element:', objectContext.element.name) }})// Path changes - single parametersubscribeToEvent('environment.path.changed', (path) => { console.log('Path changed:', path)})// User events - objectContext includes contextual datasubscribeToEvent('auth.user.event', (eventData, objectContext) => { console.log('User event:', eventData.type) if (objectContext.course) { console.log('Happened in course:', objectContext.course.name) }})
Available Events:
Event
Parameters
Description
environment.viewport.changed
(viewport, objectContext)
User navigated to a different viewport. objectContext contains course/module/element data based on permissions.
Objects are only present when the permission is granted and the viewport context matches.
How it works:
Objects are included based on two conditions:
Permission granted: Your app must have the corresponding permission declared in the manifest
Relevant context: The current viewport/path must be within that context
When both conditions are met, the complete object is included. Otherwise, the key is not present in the object.
Example:
Code
// With course_read permission on a course detail page:{ course: { id: "abc123", name: "Introduction to React", /* ...other course fields */ } // module and element keys not present (not in their context)}// Without course_read permission on a course detail page:{ // No keys present (no permissions granted)}// With course_read and module_read on a module detail page:{ course: { id: "abc123", name: "Introduction to React", /* ...other course fields */ }, module: { id: "def456", name: "Getting Started", /* ...other module fields */ } // element key not present (not in element context)}
See Permissions for details on requesting access to course, module, and element data.
Data Storage
The Extension Kit provides store(), retrieve(), and createCollection() functions for persisting data. Three types of storage are available: app data (organization-wide), user data (user-specific), and user collections (paginated lists).
See Data Storage for complete documentation, API reference, and usage examples.
import { goToViewport } from '@teachfloor/extension-kit'// Navigate to coursesfunction goToCourses() { goToViewport('teachfloor.dashboard.course.list')}// Navigate to settingsfunction goToSettings() { goToViewport('teachfloor.dashboard.settings.general.detail')}// Navigate to accountfunction goToAccount() { goToViewport('teachfloor.dashboard.account.detail')}
Deeplinking
Use goToPath when you already have a fully-resolved in-app path — typically captured from environment.path — and want to deeplink the user back to it (e.g. a saved bookmark or a "back to where you were" button).
Code
import { goToPath, useExtensionContext } from '@teachfloor/extension-kit'// Save the current path...const { environment } = useExtensionContext()const savedPath = environment.path // e.g. "/org-slug/courses/123/modules/456"// ...and deeplink back latergoToPath(savedPath)
Rules and guards:
path must be a relative path beginning with a single / (no protocol-relative //…, no absolute URLs). Anything else is ignored.
The path must belong to the current organization — deeplinks whose first segment doesn't match the user's org slug are rejected, so an app installed in one org can't redirect the user into another.
On custom domains, the org slug is stripped from the URL automatically — paths captured from environment.path work on both URL shapes.
AI Generation
Text Generation
Generate text using AI models with the platform's built-in AI capabilities.
Code
import { generate } from '@teachfloor/extension-kit'// Generate textasync function generateContent() { try { const result = await generate( 'Write a summary of this course', 'ai/text-generate' ) console.log(result) // Generated text response return result } catch (error) { console.error('Generation failed:', error) }}
Parameters:
prompt (string, required): The prompt to send to the AI model. Can include placeholders like {{course.content}}
generationType (string, optional): Type of generation (default: 'ai/text-generate')
Available Generation Types:
'ai/text-generate': General text generation
Permissions Required:
ai_text_generate: Always required to use AI generation
ai_context_external_send: Only required when using placeholders
Contextual permissions: Required for corresponding placeholders (course_read for course placeholders, etc.)
Using Placeholders
Include platform data directly in prompts using placeholders:
Code
import { generate } from '@teachfloor/extension-kit'// Course placeholders (requires: ai_text_generate + course_read + ai_context_external_send)const courseSummary = await generate( 'Summarize this course: {{course.content}}')// Module placeholders (requires: ai_text_generate + module_read + ai_context_external_send)const moduleQuiz = await generate( 'Create a 5-question quiz about {{module.name}}: {{module.content}}')// Element placeholders (requires: ai_text_generate + element_read + ai_context_external_send)const studyNotes = await generate( 'Generate study notes for {{element.name}}: {{element.content}}')
Supported Placeholders:
{{course.name}} - Course title
{{course.content}} - Course content (text format)
{{module.name}} - Module title
{{module.content}} - Module content (text format)
{{element.name}} - Element title
{{element.content}} - Element content (text format)
Without Placeholders
You can also manually include context data (only requires ai_text_generate):