Skip to main content

Runtime Tags (ui:*)

Tags are labels you put on a component in the dashboard, the CLI or the MCP tools. Most tags are for your team: ownership, status, internal system names. Tags that start with ui: are also readable by your host app at runtime. You can use them to switch behaviour in your app without a code change, for example by showing a "beta" badge, picking a layout or tagging analytics events.

import { preloadComponents, getComponentTags } from '@myop/sdk/helpers';

await preloadComponents(['my-component-id']);
getComponentTags('my-component-id'); // ['ui:beta', 'ui:layout-wide']

The rule: only ui: leaves Myop​

Tag on the componentReadable at runtime?
ui:beta✅ yes
ui:layout-wide✅ yes
UI:beta, Ui:beta❌ no (the prefix is lowercase and case-sensitive)
uibeta, ui-beta, ui❌ no (the colon is required)
system ABC, owner:payments, internal❌ no, never

Myop's servers apply this filter before anything reaches the browser. Tags without the ui: prefix are never sent to the SDK, and no query parameter or SDK option can change that.

ui: tags are public

A component's runtime data is served to anyone who loads your page, so treat every ui: tag as public. Put nothing in a ui: tag that you would not show in your page source: no internal system names, customer names or secrets. Use tags without the prefix for those; they stay private.

Adding a ui: tag​

Add it like any other tag:

  • Dashboard: the component's tag editor.
  • CLI: myop tags add ui:beta (see myop tags).
  • MCP: the edit_component_tags tool, e.g. { componentId, add: ["ui:beta"] }.

Tags belong to the component, not to a version or an environment. You don't need to save a new version or release one: the next page load picks up the change.

Reading tags in the host app​

Tags come with the component itself, in the same response the SDK already fetches to render it. There is no extra request, and a component without ui: tags costs nothing extra.

getComponentTags(componentId, env?, preview?)​

This is a synchronous read from the SDK's cache. It returns [] when the component has no ui: tags or hasn't been fetched yet. It never throws and never makes a request.

import { preloadComponents, getComponentTags } from '@myop/sdk/helpers';

await preloadComponents(['my-component-id']);

if (getComponentTags('my-component-id').includes('ui:beta')) {
showBetaBadge();
}

Pass the same env / preview you used to load the component if you load it with explicit values. With no arguments it uses the same defaults as preloadComponents.

From the cloud repository, before loading the component​

If you fetch the config yourself, you can read the tags from it before you decide whether, or how, to render the component:

import { getCloudRepository, getComponentTags } from '@myop/sdk/helpers';
import { getHostModule } from '@myop/sdk';

// One request, the same one loadComponent would make, cached for this page
const config = await getCloudRepository().fetchComponentV2('my-component-id');

const tags = config.type.uiTags ?? []; // ['ui:beta']
// or, equivalently: getComponentTags('my-component-id')

if (!tags.includes('ui:hidden')) {
const { hostSDK } = await getHostModule();
const component = await hostSDK.loadComponent(config, container); // no second request
}

fetchComponentV2(componentId, env?, preview?) takes the same env / preview arguments as getComponentTags. When you create your own repository with new CloudRepository(url), the same two reads work on that instance: repo.fetchComponentV2(id) returns the config, and repo.getComponentTags(id) returns its tags.

component.uiTags​

Every mounted component exposes its tags directly:

import { getHostModule } from '@myop/sdk';

const { hostSDK } = await getHostModule();
const component = await hostSDK.loadComponent(componentConfig, container);

component.uiTags; // ['ui:beta'] (always an array, [] when there are none)

Server-side rendering and hydration​

If you resolve configs on a server and hydrate them in the browser, the tags travel inside the config. Nothing extra is needed: getComponentTags works on hydrated components with no network round trip.

Preview and released versions​

Tags are the same in preview and in every environment, because they belong to the component and not to a release. A component that is only in preview still returns its tags.

Self-hosting​

Self-hosted exports include each component's ui: tags, filtered the same way. Re-export after changing tags so your static files pick up the change.

Good uses, and what not to use them for​

Good uses:

  • Feature flags and badges: ui:beta, ui:new
  • Layout or theme hints: ui:layout-wide, ui:theme-dark
  • Analytics labels: ui:campaign-q4

Not a fit:

  • Access control. Anyone can read the tags, so never use them to decide what a user is allowed to see.
  • Large or frequently changing data. Use the component's data (myop_init_interface) for that.

Requirements and limits​

  • @myop/sdk 0.3.37 or later. Older SDKs ignore the field, so nothing breaks.
  • Framework wrappers (@myop/react, @myop/vue, @myop/angular, @myop/react-native) don't expose tags yet. Use @myop/sdk directly for now.
  • At most 50 ui: tags per component, each up to 100 characters. Duplicates are removed and the order you set is kept.