Creating a "Hello, World" Extension
Extensions let you package scripts — together with resources like bitmaps or data tables — into a single file that installs into Tabular IQ. Once installed, an extension runs automatically every time the application starts, so it can add functionality that feels native, such as its own menu items and panels.
This guide builds the classic first extension: a Hello World… item in the Tools menu that shows a message when clicked.
Creating the main script
Every extension has a startup script, conventionally named main.js. Ours does three things:
- Checks whether it’s running as an installed extension, using
Extension.isContextPackage(). This lets the same file run standalone while you develop it. - When packaged, inserts a menu item into the Tools menu and connects its click event.
- Shows the alert when the menu item is clicked.
Create a file named main.js:
if (Extension.isContextPackage())
{
// the script is packaged as an installed extension: add a
// menu item to the host application and connect its click
// event to a handler
const item = insertToolsMenuItem("Hello World...");
if (item)
item.click.connect(onHelloWorldMenuItemClicked);
}
else
{
// the script is running standalone (e.g. during development):
// simply show the message
alert("Hello World");
}
// start the event loop so the menu item's click event
// can be processed
Application.run();
function onHelloWorldMenuItemClicked()
{
alert("Hello World");
}
function insertToolsMenuItem(name)
{
// inserts a menu item near the bottom of the Tools menu,
// just above the separator that precedes "Options..."
// "menu.tools" is the Tools menu's name, which never changes;
// getMenu returns null if this host has no such menu
const tools_menu = HostApp.getMenu("menu.tools");
if (!tools_menu)
return null;
// if the item already exists (for example, the extension was
// restarted), remove the old one first; findMenuItem returns
// the item's index, or -1 if not found
const existing = tools_menu.findMenuItem(name);
if (existing >= 0)
tools_menu.remove(existing);
const item = new MenuItem(name);
// "app.options" is the command behind the Options... item; asking
// for it by command rather than by caption is what makes this work
// in every language the application ships in
const options_pos = tools_menu.findMenuItemByCommand("app.options");
if (options_pos >= 1)
{
// insert above the separator preceding Options...
tools_menu.insert(item, options_pos - 1);
}
else
{
// this host arranges its Tools menu differently; append
// rather than guess at a position
tools_menu.add(item);
}
return item;
}
You can run main.js as a plain script right now (Alt+Enter) — because it isn’t packaged yet, isContextPackage() returns false and it simply shows the alert.
Finding menus and items
The two lookups above both use names, not the text on screen:
| Call | Finds | Why not the caption |
|---|---|---|
HostApp.getMenu("menu.tools") | The host’s Tools menu | The caption is translated — it reads “Extras” in a German installation — and the menu’s position in the menu bar shifts as documents are opened and closed. |
menu.findMenuItemByCommand("app.options") | The item that opens Options… | Same translation problem, plus the caption can be reworded between releases. |
The available menu names are menu.file, menu.edit, menu.view, menu.data, menu.tools and menu.help. A host application isn’t required to provide all of them, so check the result of getMenu() before using it.
Command names such as app.options and app.extension_manager identify the host’s own commands. findMenuItemByCommand() returns -1 when the menu holds no item for that command, which is also what you get for a command the host doesn’t define — so treat -1 as “place it somewhere sensible instead”, as the code above does.
Your own menu items don’t carry a host command, so keep using findMenuItem() for those: you chose their captions, so matching on them is safe.
Creating the info file
Alongside main.js, every extension needs an info.xml file carrying its metadata:
<?xml version="1.0"?>
<extension_info>
<guid>{9642c44c-f790-4f16-9d46-fb54fc97d1a7}</guid>
<name>Hello World Extension</name>
<author>Hello World Industries, Inc.</author>
<bitmap>icon.png</bitmap>
<startup>main.js</startup>
<copyright>(c) 2026 Hello World Industries, Inc.</copyright>
<description>A simple "Hello World" extension.</description>
<major_version>1</major_version>
<minor_version>0</minor_version>
<subminor_version>0</subminor_version>
</extension_info>
The fields are:
| Field | Meaning |
|---|---|
guid | Unique ID for the extension. Generate a fresh GUID for each extension you create — don’t reuse the one above. |
name | Name shown in the Extensions panel. |
author | Author of the extension. |
bitmap | Icon shown in the Extensions panel (optional; include the file in the package). |
startup | The script file run when the extension starts — main.js here. |
copyright | Copyright information. |
description | Description shown in the Extensions panel. |
major_version / minor_version / subminor_version | Version number shown in the Extensions panel. |
What goes into the package
An extension file is simply a zip archive renamed to .kxt. It must contain at least:
info.xml— the metadata file abovemain.js— the startup script (whatever name thestartupfield points at)
It may also contain:
- as many additional JavaScript source files as you like, referenced from your code
- resource files (bitmaps, text, data) referenced from your code
- the bitmap named in the
bitmaptag, for display in the Extensions panel
Packaging and installing
- Compress
main.jsandinfo.xmlinto a.zipfile. - Rename the file’s extension from
.zipto.kxt. - In Tabular IQ, choose Extensions… from the Tools menu.
- Click Add Extension… and select your
.kxtfile. - Start the extension. From now on, it runs automatically every time Tabular IQ launches.
Open the Tools menu: there’s your Hello World… item, sitting above Options… as if it had always been there.
Next steps
- API Overview — the Host Application category is the heart of most extensions
- HostApp class reference — menus, panes, documents, and the project database
- Extension class reference — package context and resource access