Developing your first Koji template (2025)

On the Koji platform, you can develop JavaScript web applications that can be customized without coding.Instead, non-technical users can use Visual Customization Controls (VCCs) to quickly edit elements of the application, such as images, text, and sounds.

In this starter guide, you will start with an existing web application on Koji, called a “template,” and add the ability to customize, or “remix,” it.You will use the Koji editor and an npm package from Koji to define the customizable elements.Then, you will publish your application as a new template so that Koji users can create their own customized versions of it.

Remixing the starter scaffold

  1. If you haven’t already, create an account at withkoji.com.

  2. Open a starter scaffold that implements basic elements of your favorite framework.

    React

    Vanilla JS

    Angular

    Svelte

    React

    React scaffold

    Vanilla JS

    Vanilla JS scaffold

    Angular

    Angular scaffold

    Svelte

    Svelte scaffold

  3. Click the Koji button in the top right, and then click Advanced > Fork.

    Developing your first Koji template (1)

    This action creates a clone of the starter scaffold and opens it in the Koji editor.

  4. Explore the template and the Koji editor.

    • In the right pane, you can see a live preview of the template.

    • In the left pane, you can click Source Code to expand the file browser.From here, you can open and edit your project files in the editor.

    • At the bottom, you can expand a set of terminal tabs.These tabs enable you to run the template locally from inside the editor and to execute other terminal functions, such as adding packages and committing changes.

      Note

      If you make changes to your project’s structure (by adding npm packages, for example), you might need to cancel the running process and restart the development server in the frontend terminal.

Installing the @withkoji/vcc package

The @withkoji/vcc package allows your template to access dynamic values that are stored in customization files.It also allows you to expose VCCs so that a user can change the customizable items in your template.Finally, it provides a watcher function that allows you to monitor changes to customization files and perform a real-time set of the dynamic values stored in the customization files.

  1. Open the frontend terminal, and cancel the running process (for example, press Ctrl+C).

  2. Install the latest version of the package.

    npm install --save @withkoji/vcc
  3. Reconfigure the package.json file to run the watcher concurrently with your development server.You can use a package like npm-run-all.For example:

    Install npm-run-all.

    npm install --save-dev npm-run-all

    Modify the package.json file.

    React

    Vanilla JS

    Angular

    Svelte

    React

    { "scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "webpack-dev-server --config ./.internals/webpack.development.js --inline --hot" }}

    Vanilla JS

    { "scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "webpack-dev-server --config ./.internals/webpack.development.js --inline --hot" }}

    Angular

    "scripts": { ... "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "cross-env NODE_ENV=development ng serve --host 0.0.0.0 --port 4200 --disableHostCheck=true", ...}

    Svelte

    "scripts": { "start": "npm-run-all -p watch start:server", "watch": "koji-vcc watch", "start:server": "parcel src/index.html -p 8080", ...}

    Warning

    Make sure to replace the value of "start:server" with the "start" command for your project and remove the prestart command, if there is one.
  4. Restart the process to reflect the new changes.

    npm start

Creating a customization file

A customization file is a JSON file that defines the names and types of the customizable values in a template, so that Koji can display the appropriate VCCs for remixers.

  1. In the .koji/customization folder of your project, create a new JSON file.

    1. In the file browser, click the plus (+) next to the .koji/customization folder, and click New file.

    2. Enter a name for the file.For example: settings.json.

  2. Paste the following code into your settings.json file.

    This code defines a scope and the customizable values within that scope.

    { "settings": { "title": "Hello World!"},"@@editor": [ { "key": "settings", "name": "App settings", "icon": "⚙️", "source": "settings.json", "fields": [ { "key": "title", "name": "App title", "type": "text" } ] } ] }
  3. Press Ctrl-S to save the file.

    A new item appears in the VCC Explorer section of the left pane.

  4. Click the item in the VCC Explorer section to display the associated VCC in the editor.

    In this example, the file stores one customizable value (settings.title), and Koji displays a text VCC to collect this value from a remixer.

Accessing the values stored in a customization file

To access a value from a JSON customization file within a template, you use a getter from the @withkoji/vcc package.Then, update the template to use dynamic values, instead of hard-coded values.

  1. From the left pane of the editor, open the file that contains the template logic.

    React

    Vanilla JS

    Angular

    Svelte

    React

    frontend/common/App.js

    Vanilla JS

    frontend/index.js

    Angular

    frontend/src/app/app.component.ts

    Svelte

    src/App.svelte

  2. At the top of the file, import the package.

    React

    Vanilla JS

    Angular

    Svelte

    React

    import { InstantRemixing } from '@withkoji/vcc';

    Vanilla JS

    import { InstantRemixing } from '@withkoji/vcc';

    Angular

    import { InstantRemixing } from '@withkoji/vcc';

    Svelte

    <script> import { InstantRemixing } from '@withkoji/vcc';</script>
  3. Create a new instance of the InstantRemixing class to use in the template and alert Koji that instant remixing is ready to use.

    React

    Vanilla JS

    Angular

    Svelte

    Example 1. React

    In the React component, add the componentDidMount method.

    componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Example 2. Vanilla JS

    Add this code above the render function definition.

    var instantRemixing = new InstantRemixing();// Alert Koji we are ready to use instantRemixinginstantRemixing.ready();

    Example 3. Angular

    In the Angular component, add a new property and update the ngOnInit method.

    export class AppComponent implements OnInit { instantRemixing = null; ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); }}

    Example 4. Svelte

    Add the onMount method.

    <script> import { onMount } from 'svelte'; import { InstantRemixing } from '@withkoji/vcc'; let instantRemixing; let title; onMount(() => { instantRemixing = new InstantRemixing(); // Alert Koji we are ready to use instantRemixing instantRemixing.ready(); });</script>
  4. Update the contents of the h1 element to use the dynamic title value.

    React

    Vanilla JS

    Angular

    Svelte

    Example 5. React

    Create a state to handle updates to the title value.

    class App extends React.Component { state = { title: '', }; ... render() { return ( <Container> <h1>{this.state.title}</h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> ); }}

    Example 6. Vanilla JS

    Add an id attribute to access the element more easily in the next step.

    // render appconst render = () => { document.body.innerHTML = ` <h1 id="title">${title}</h1> <img id="logo" src="https://images.koji-cdn.com/e62ec06b-01be-4183-a7c0-ee6e8950f398/t5ues-600pxJavaScriptlogo.png"/> `;};

    Example 8. Angular

    app.component.ts

    app.component.html

    Example 7. app.component.ts

    Add a property to handle updates to the title value, and then update app.component.html.

    export class AppComponent implements OnInit { instantRemixing = null; title = ''; ...}

    app.component.html

    <div class="container"> <h1>{{title}}</h1> <img class="image" src="https://images.koji-cdn.com/cf19e146-554d-459e-96a1-b36b71eda51e/userData/gi3e2wscdw-b8ae90b11dbb4339a93af61c9e0a2100.png" /></div>

    Svelte

    <h1>{title}</h1>
  5. Use the getter function from instantRemixing to get the default value from the customization file.

    The getter accepts an array ([scope, key]) that maps to the scope (settings) and key (title) from the JSON customization file.

    React

    Vanilla JS

    Angular

    Svelte

    React

    componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ title: this.instantRemixing.get(['settings', 'title']) }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Example 9. Vanilla JS

    Create a variable to handle updates to the title value.

    var title = instantRemixing.get(['settings', 'title']);

    Angular

    ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.title = this.instantRemixing.get(['settings', 'title']); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Svelte

    onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value title = instantRemixing.get(['settings', 'title']); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});

Reacting to updated values

When a remixer enters a new value, the template must update automatically to reflect the change.

  • Set up a listener to monitor for changes to the template value.

    React

    Vanilla JS

    Angular

    Svelte

    Example 10. React

    Add the listener in the componentDidMount method.

    componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Example 11. Vanilla JS

    Add the listener below the render function call.

    // Add a listener to the on change event of instant remixing to update the titleinstantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[0] === 'settings' && path[1] && path[1] === 'title') { let titleElement = document.getElementById('title'); titleElement.textContent = newValue; }});

    Example 12. Angular

    Add the listener in the ngOnInit method.

    ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Example 13. Svelte

    Add the listener in the onMount method.

    onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});

    Tip

    Make sure to set up your listeners before calling the ready method.The Koji platform will queue any messages before the ready call to wait for the listeners to be ready.

Testing the current state of the template

At this point, the template should be configured to use the default value from the customization file and to react to value changes that are made from VCCs.To test this configuration, you can use the built-in VCC and live preview in the Koji editor.

  1. In the top right of the Live Preview pane, click Refresh to make sure you are seeing the latest version.

  2. From the left pane of the editor, click VCC Explorer > App Settings to open the VCC for the settings.json customization file.

  3. In the VCC, update the value in the App title field.

    The preview window should reflect your update automatically.

Determining the current view of the template

The template must display differently and expose different click handlers depending on whether a user is viewing or customizing the template.In this example, you will add styles to show that the h1 element is editable and a click handler to expose a VCC when a user is customizing the template.

  1. Create a property (isRemixing) to track the current view state, if needed.

    React

    Vanilla JS

    Angular

    Svelte

    React

    state = { isRemixing: false, title: '',};

    Vanilla JS

    Not needed

    Angular

    instantRemixing = null;title = '';isRemixing = false;

    Svelte

    let isRemixing;
  2. Add a listener that monitors the template for view changes between remixing and viewing.

    React

    Vanilla JS

    Angular

    Svelte

    Example 14. React

    In the setState function, set the default value for this.instantRemixing.isRemixing, and then add the listener to maintain it as a source of truth for the current view.

    componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.setState({ isRemixing: this.instantRemixing.isRemixing, title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.setState({ isRemixing }); }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Example 15. Vanilla JS

    // Add a listener to handle state changes between remixing and notinstantRemixing.onSetRemixing((isRemixing) => { if (isRemixing) { startRemix(); } else { stopRemix(); }});

    Note

    You will add implementations of startRemix and stopRemix in subsequent steps.

    Angular

    ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.isRemixing = this.instantRemixing.isRemixing; this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.isRemixing = isRemixing; }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready();}

    Svelte

    onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value for title and isRemixing state isRemixing = instantRemixing.isRemixing; title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Toggle the isRemixing state based on the listener instantRemixing.onSetRemixing((isRemixingTrue) => { isRemixing = isRemixingTrue; }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready();});

Exposing the VCC

The template must expose a way for a remixer to open the VCC when customizing it.

  • Add a click handler that opens the VCC when the remixer clicks the title (h1 element).

    React

    Vanilla JS

    Angular

    Svelte

    React

    handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.state.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); }};render() { return ( <Container> <h1 onClick={this.handleClick}>{this.state.title}</h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> );}

    Vanilla JS

    // Add click event listener to expose title VCCdocument.addEventListener('click', function (event) { if (!event.target.matches('#title')) return; event.preventDefault(); instantRemixing.onPresentControl(['settings', 'title']);});

    Example 16. Angular

    app.component.ts

    app.component.html

    app.component.ts

    handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); }};

    app.component.html

    <div class="container"> <h1 (click)="handleClick()">{{title}}</h1> <img class="image" src="https://images.koji-cdn.com/cf19e146-554d-459e-96a1-b36b71eda51e/userData/gi3e2wscdw-b8ae90b11dbb4339a93af61c9e0a2100.png" /></div>

    Svelte

    function editText() { // Conditionally handle the click, only if the template is being remixed if (isRemixing) { instantRemixing.onPresentControl(['settings', 'title']); }};...<h1 on:click={editText}>{title}</h1>

Testing the expose function

To test whether the expose function is working, you can use the Editing tab of the Live Preview pane.This feature enables you to test the template as if it were published on Koji.

  1. In the Live Preview pane, click Editing to switch to the template editing mode.

  2. Click the title in the preview.

    The VCC should open automatically and allow for text input.If this test works correctly, the VCC should be exposed correctly to the remixer in your published template.

Styling the customizable item

To indicate that an item is “editable,” you can add a conditional visual effect that is displayed when the template is being customized.In this example, you’ll add a CSS style class for editable items and then apply the class to the h1 when a user is customizing the template.

  1. From the left pane of the editor, open the following file.

    React

    Vanilla JS

    Angular

    Svelte

    React

    frontend/common/index.html

    Vanilla JS

    frontend/style.css

    Angular

    frontend/src/app/app.component.scss

    Svelte

    src/App.svelte

  2. Add the following style definition.

    React

    Vanilla JS

    Angular

    Svelte

    React

    <style> .active { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style>

    Vanilla JS

    .edit { border: 2px dashed grey;}

    Angular

    .active { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px;}

    Svelte

    <style> .remixing { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style>
  3. Update the h1 element with dynamic styling.

    React

    Vanilla JS

    Angular

    Svelte

    Example 17. React

    In the App.js file, use a dynamic className.

    <h1 className={this.state.isRemixing ? 'active' : ''} onClick={this.handleClick} > {this.state.title}</h1>

    Example 18. Vanilla JS

    Add implementations of startRemix and stopRemix that modify the class name of the h1 element, for simplicity in this tutorial.

    // Modify elements to display state for remixingconst startRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.add('edit');};// Modify elements to display state for previewingconst stopRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.remove('edit');};

    Example 19. Angular

    In the app.component.html file, use a dynamic class.

    <h1 class="{{isRemixing ? 'active' : ''}}" (click)="handleClick()"> {{title}}</h1>

    Svelte

    <h1 class={isRemixing ? 'remixing' : ''} on:click={editText}> {title}</h1>
  4. To test the dynamic styling, you can toggle the live preview between the Editing and Preview modes.

    • In Editing mode, the “editable” styles should be visible, and the click handler should open the VCC, as expected.

    • In Preview mode, the “editable” styles should not be visible, and nothing should happen when clicking the h1 element.

Making the template “feed-aware”

Koji uses a feed to enable users to browse available templates.As with traditional social feeds, items move from off screen or out of focus, into the main window inside the feed.To ensure the template is displayed correctly in the Koji feed, you use the FeedSdk from the @withkoji/vcc package to set the template state and handle transitions between on and off screen and in and out of focus.

  1. Import the FeedSdk from the @withkoji/vcc package.

    import { FeedSdk, InstantRemixing } from '@withkoji/vcc';
  2. Add the following code to display the template in the feed.

    React

    Vanilla JS

    Angular

    Svelte

    Example 20. React

    Add this code at the end of the componentDidMount method.

    this.feed = new FeedSdk();this.feed.load();

    Example 21. Vanilla JS

    Add this code below the render function call.

    var feed = new FeedSdk();feed.load();

    Example 22. Angular

    Add a new property, and add code at the end of the ngOnInit method.

    export class AppComponent implements OnInit { ... feed = null; ngOnInit() { ... this.feed = new FeedSdk(); this.feed.load(); }}

    Example 23. Svelte

    Add this code at the end of the onMount method.

    let feed = new FeedSdk();feed.load();

    This code creates an instance of the feed and calls a load function to indicate that the template is ready to be displayed in the feed, which is all that is required when the template does not use autoplay.

    Note

    If you plan to develop templates that autoplay when focused in the feed, you can use the onPlaybackStateChanged listener to monitor for real-time updates as the template enters and leaves focus in the feed, similar to how this example uses onSetRemixing.

Adding entitlements for the Koji profiler

When you publish the template, it is submitted into a queue for profiling.The Koji profiler checks for errors and generates metadata about the application.If the template is error-free, the profiler enables additional platform features for your template, including the instant remix option and inclusion in the feed.To prepare your template to be profiled correctly, you must add entitlements for some of these features.

  • In the .koji/project folder, create an entitlements.json file with the following code:

    { "entitlements": { "InstantRemixing": true, "FeedEvents": true }}

    This code indicates that the template supports remixes and is ready to be listed in the feed.

Publishing the template

At this point, the template is ready to be published.

  1. To preview the template on the staging server before you publish it, you can click the remote staging button Developing your first Koji template (2) in the preview pane to open the preview in a new tab.

  2. To preview the template on a mobile device, you can click the QR code button Developing your first Koji template (3) in the preview pane to display the QR code, then scan the code with your mobile device.

  3. In the upper left of the editor, click Publish Now to open the publish settings.

  4. Give your template a unique name and add a description.

    Note

    The permalink URL to your template is based on the name when you first publish it, so be sure to enter the name you want to use going forward.You can republish it to update any template functionality and settings, but the link remains the same.
  5. Click Publish New Version.

    A message appears to indicate that the publishing process has started.When publishing is completed, a link appears in the message.

  6. Click the link to view and test your live template.

    The template might be published before profiling is completed.Therefore, you might need to wait longer before testing features that require profiling, such as inclusion in the feed or the ability to instantly remix the template.To see the results of the most recent profiling, from your live template, click the Koji button, and then click More > Developer Tools.Select the attributes you want to see, such as Content Audit or Entitlements.

    If an error message appears when you open the link after profiling is completed, you can review the steps in this guide to fix it.

Completed samples and next steps

In this guide, you learned how to add basic customizable elements to a template and then publish it on Koji.

  • To troubleshoot any issues with your template, you can compare your code to this completed sample of the logic described in this guide.

    React

    Vanilla JS

    Angular

    Svelte

    Example 24. React

    frontend/common/App.js

    import React from 'react';import styled from 'styled-components';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';const Container = styled.div` background-color: #395b88; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); text-align: center; color: #fcfcfc;`;const Image = styled.img` max-width: 50vmin; max-height: 50vmin;`;class App extends React.Component { state = { isRemixing: false, title: '', }; componentDidMount() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value this.setState({ isRemixing: this.instantRemixing.isRemixing, title: this.instantRemixing.get(['settings', 'title']) }); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.setState({ title: newValue }); } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.setState({ isRemixing }); }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); this.feed = new FeedSdk(); this.feed.load(); } handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.state.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); } }; render() { return ( <Container> <h1 className={this.state.isRemixing ? 'active' : ''} onClick={this.handleClick} > {this.state.title} </h1> <Image src={'https://images.koji-cdn.com/d9c6b38e-08c4-4faf-ae8e-01082c41a0fb/3f83q-9634d620e97345a6b250ca2feb7e5a2e.png'} /> </Container> ); }}export default App;

    Example 25. Vanilla JS

    frontend/index.js

    import './styles.css';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';var instantRemixing = new InstantRemixing();var title = instantRemixing.get(['settings', 'title']);// render appconst render = () => { document.body.innerHTML = ` <h1 id="title">${title}</h1> <img id="logo" src="https://images.koji-cdn.com/e62ec06b-01be-4183-a7c0-ee6e8950f398/t5ues-600pxJavaScriptlogo.png"/> `;};// Modify elements to display state for remixingconst startRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.add('edit');};// Modify elements to display state for previewingconst stopRemix = () => { let titleElement = document.getElementById('title'); titleElement.classList.remove('edit');};var feed = new FeedSdk();feed.load();// Add a listener to the on change event of instant remixing to update the titleinstantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[0] === 'settings' && path[1] && path[1] === 'title') { let titleElement = document.getElementById('title'); titleElement.textContent = newValue; }});// Add a listener to handle state changes between remixing and notinstantRemixing.onSetRemixing((isRemixing) => { if (isRemixing) { startRemix(); } else { stopRemix(); }});// Add click event listener to expose title VCCdocument.addEventListener('click', function (event) { if (!event.target.matches('#title')) return; event.preventDefault(); instantRemixing.onPresentControl(['settings', 'title']);});// Alert Koji we are ready to use instantRemixinginstantRemixing.ready();// renderrender();

    Example 26. Angular

    frontend/src/app/app.component.ts

    import { Component, OnInit } from '@angular/core';import { FeedSdk, InstantRemixing } from '@withkoji/vcc';@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'],})export class AppComponent implements OnInit { instantRemixing = null; title = ''; isRemixing = false; feed = null; ngOnInit() { this.instantRemixing = new InstantRemixing(); console.log('instantRemixing', this.instantRemixing); // Confirm w/log // Set the default value for title and isRemixing state this.isRemixing = this.instantRemixing.isRemixing; this.title = this.instantRemixing.get(['settings', 'title']); // Set up a listener to update title value this.instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { this.title = newValue; } }); // Toggle the isRemixing state based on the listener this.instantRemixing.onSetRemixing((isRemixing) => { this.isRemixing = isRemixing; }); // Alert Koji we are ready to use instantRemixing this.instantRemixing.ready(); this.feed = new FeedSdk(); this.feed.load(); } handleClick = () => { // Conditionally handle the click, only if the template is being remixed if (this.isRemixing) { this.instantRemixing.onPresentControl(['settings', 'title']); } };}

    Example 27. Svelte

    src/App.svelte

    <script> import { onMount } from 'svelte'; import { FeedSdk, InstantRemixing } from '@withkoji/vcc'; let instantRemixing; let title; let isRemixing; onMount(() => { instantRemixing = new InstantRemixing(); // Set the default value for title and isRemixing state isRemixing = instantRemixing.isRemixing; title = instantRemixing.get(['settings', 'title']); // Set up a listener to update title value instantRemixing.onValueChanged((path, newValue) => { if (path[0] && path[1] && path[0] === 'settings' && path[1] === 'title') { title = newValue; } }); // Toggle the isRemixing state based on the listener instantRemixing.onSetRemixing((isRemixingTrue) => { isRemixing = isRemixingTrue; }); // Alert Koji we are ready to use instantRemixing instantRemixing.ready(); let feed = new FeedSdk(); feed.load(); }); function editText() { // Conditionally handle the click, only if the template is being remixed if (isRemixing) { instantRemixing.onPresentControl(['settings', 'title']); } };</script><style> .remixing { background-color: rgba(255, 255, 255, 0.4); padding: 18px; border-width: 1px; border-style: solid; border-color: rgb(255, 255, 255); border-image: initial; border-radius: 4px; }</style><div class="image" style='background-image: url("https://images.koji-cdn.com/43188147-b060-443f-b76a-9fddd4b93f38/p6a4a-a6471bdde6154e5ab793a13c5dfcd81c.png?optimize=50");'></div><h1 class={isRemixing ? 'remixing' : ''} on:click={editText}> {title}</h1>
  • To continue working on this project and learn how to create a complete and compelling Koji template, see start-guide-2.html.

Developing your first Koji template (2025)
Top Articles
Latest Posts
Recommended Articles
Article information

Author: Kimberely Baumbach CPA

Last Updated:

Views: 5686

Rating: 4 / 5 (61 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Kimberely Baumbach CPA

Birthday: 1996-01-14

Address: 8381 Boyce Course, Imeldachester, ND 74681

Phone: +3571286597580

Job: Product Banking Analyst

Hobby: Cosplaying, Inline skating, Amateur radio, Baton twirling, Mountaineering, Flying, Archery

Introduction: My name is Kimberely Baumbach CPA, I am a gorgeous, bright, charming, encouraging, zealous, lively, good person who loves writing and wants to share my knowledge and understanding with you.