Skip to main content

Theme Template Variables

This page is the complete reference for all values and template placeholders available to theme developers.

Themes use a double-bracket syntax: [[variable]]. This is distinct from the single-bracket handlebars syntax {{placeholder}} used inside app template files.

Theme values and app runtime values are related but not identical:

  • themes use [[user.*]] and templateData.user
  • apps use the shared runtime profile object available through window.__shuukaCtx.profile, window.shuukaConfig.profile, or native app props

This separation lets all theme types keep their existing flow while apps reuse the same normalized owner identity payload.


Syntax Overview​

SyntaxUsed inPurpose
[[variable]]Theme HTML templatesInjects a platform or user value
[[IF condition]]…[[/IF]]Theme HTML templatesConditional block
[[IF condition]]…[[ELSE]]…[[/IF]]Theme HTML templatesConditional with fallback
{{placeholder_key}}App template.htmlApp instance setting value (apps only)

User Values​

These values describe the profile owner and are always available in the theme.

VariableTypeDescription
[[user.name]]stringFull display name
[[user.nickname]]stringPublic handle (without @)
[[user.avatar_url]]stringAvatar image URL
[[user.cover_image_url]]stringCover / header image URL
[[user.description]]stringProfile bio / description
[[user.category]]stringProfile category label
[[user.verification_badge]]HTML stringPlatform-rendered verification badge markup
[[user.public_id]]stringPublic profile identifier
[[user.locale]]stringActive locale, e.g. en

Usage example​

<header class="profile-header">
[[IF settings.show_avatar]]
<img class="avatar" src="[[user.avatar_url]]" alt="[[user.name]]">
[[/IF]]

[[IF settings.show_title]]
<h1 class="profile-name">[[user.name]]</h1>
[[/IF]]

[[IF settings.show_nickname]]
<p class="profile-handle">@[[user.nickname]]</p>
[[/IF]]

[[IF settings.show_description]]
<p class="profile-bio">[[user.description]]</p>
[[/IF]]
</header>

Settings Visibility Flags​

These booleans reflect what the profile owner has enabled. Always wrap optional content in these guards.

VariableTypeDescription
[[settings.show_title]]booleanWhether to render the display name
[[settings.show_avatar]]booleanWhether to render the avatar
[[settings.show_nickname]]booleanWhether to render the handle
[[settings.show_category]]booleanWhether to render the category label
[[settings.show_description]]booleanWhether to render the bio
[[settings.show_cover_image]]booleanWhether to render the cover image
[[settings.show_links]]booleanWhether links exist and should render
[[settings.show_apps]]booleanWhether apps exist and should render
[[settings.show_footnote]]booleanWhether to show the platform footnote

Usage example​

[[IF settings.show_cover_image]]
<div class="cover" style="background-image: url('[[user.cover_image_url]]')"></div>
[[/IF]]

[[IF settings.show_links]]
<nav class="links-section">
[[links.markup]]
</nav>
[[/IF]]

[[IF settings.show_apps]]
<section class="apps-section">
[[apps.markup]]
</section>
[[/IF]]

Rendered Markup Slots​

These are pre-rendered HTML blocks provided by the platform. Drop them into your template where you want the platform-managed content to appear.

VariableDescription
[[links.markup]]Rendered links list (social icons, URLs)
[[apps.markup]]Rendered app cards in a flat sequence
[[apps.rows_markup]]Platform-managed rows and columns for app layout (use this for grid/multi-column layouts)
[[layout.after_markup]]Platform-injected content after the main surface
[[layout.outside_markup]]Platform-injected content outside the main surface (e.g. platform-level overlays)

[[apps.markup]] vs [[apps.rows_markup]]​

  • Use [[apps.markup]] for a simple vertical list of app cards with no column logic.
  • Use [[apps.rows_markup]] when the platform should handle multi-column rows. The platform groups apps into row objects and renders the HTML including responsive sizing rules.

Usage example​

<main class="profile-content">
[[IF settings.show_links]]
<div class="links-grid">
[[links.markup]]
</div>
[[/IF]]

[[IF settings.show_apps]]
<div class="apps-list">
[[apps.rows_markup]]
</div>
[[/IF]]
</main>

[[layout.after_markup]]
[[layout.outside_markup]]

Layout Values​

These values reflect the current layout configuration set by the platform or the profile owner.

VariableTypeDescription
[[layout.inline_styles]]HTML stringPlatform-injected <style> block with resolved CSS custom properties
[[layout.article_class]]stringRoot class string for the theme article element
[[layout.type]]stringActive layout mode, e.g. hero, classic, sidebar, grid

Usage example​

<!DOCTYPE html>
<html lang="[[user.locale]]">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
[[layout.inline_styles]]
<link rel="stylesheet" href="./dist/theme.css">
</head>
<body>
<article class="shk-profile [[layout.article_class]]">
<!-- profile content -->
</article>
<script src="./dist/index.js"></script>
</body>
</html>

Always place [[layout.inline_styles]] in the <head> so CSS custom properties are available to your stylesheet when it loads.


Theme Config Values​

Theme config is directly readable inside the template. These values come from the user's active theme configuration.

Variable patternDescription
[[theme.config.header.show_image]]Whether to show the header image
[[theme.config.layout.structure]]Layout structure key
[[theme.config.background.color]]Background color value
[[theme.config.background.mode]]Background mode (solid, gradient, image, video)
[[theme.config.iframe.border_radius]]App card border radius
[[theme.config.iframe.background]]App card background
[[theme.config.iframe.shadow]]App card shadow
[[theme.config.links.alignment]]Link icon grid alignment
[[theme.config.links.item_size]]Link icon size in pixels

Usage example​

<div class="app-card-wrapper" style="border-radius: [[theme.config.iframe.border_radius]]px">
<!-- app content -->
</div>

For most cases, CSS custom properties from [[layout.inline_styles]] are a better approach than inlining config values as attributes.


CSS Custom Properties (Injected at Runtime)​

The platform injects these CSS custom properties into [[layout.inline_styles]]. Reference them in your theme SCSS with var(--property-name, fallback).

Wallpaper & Layout Variables​

When opting into createThemeBridge({ backgroundFallback: '...' }), the platform exposes the following layout variables automatically:

CSS VariableDescription
--shk-wallpaper-backgroundResolved final wallpaper value (can be a hex color or full gradient string)
--theme-accentProfile accent color
--theme-textProfile primary text color
--theme-mutedProfile secondary text color

App Card Variables​

These are derived from the active config.iframe settings and are used in app card styling.

CSS VariableDescription
--app-card-bgApp card background
--app-card-borderApp card border shorthand
--app-card-border-colorApp card border color
--app-card-radiusApp card border radius
--app-card-shadowApp card box shadow
--app-card-accentCTA / accent background color
--app-card-accent-textCTA / accent text color
--app-card-paddingApp card inner padding
--app-card-embed-radiusInner embed border radius (usually matches card radius)

These are derived from the active config.links settings.

CSS VariableDescription
--links-icon-sizeIcon size in pixels
--links-spacingSpace between link icons
--links-alignmentFlex alignment value: center, flex-start, flex-end

SCSS Usage Example​

// Always provide fallbacks so your theme looks correct even before
// CSS vars are injected (e.g. during Vite dev proxy mode).

.shk-profile {
background: var(--wallpaper-color, #0a0a0f);

&::before {
background-image: var(--wallpaper-image, none);
}
}

.shk-theme__app-card {
background: var(--app-card-bg, rgba(255, 255, 255, 0.06));
border: var(--app-card-border, 1px solid rgba(255, 255, 255, 0.10));
border-radius: var(--app-card-radius, 16px);
box-shadow: var(--app-card-shadow, 0 4px 24px rgba(0, 0, 0, 0.20));
overflow: hidden;
}

.shk-theme__link {
width: var(--links-icon-size, 48px);
height: var(--links-icon-size, 48px);
}

Conditional Blocks​

Use [[IF ...]] to conditionally render HTML.

Basic conditional​

[[IF settings.show_avatar]]
<img class="avatar" src="[[user.avatar_url]]" alt="">
[[/IF]]

With else branch​

[[IF settings.show_cover_image]]
<div class="cover" style="background-image: url('[[user.cover_image_url]]')"></div>
[[ELSE]]
<div class="cover cover--empty"></div>
[[/IF]]

Nested conditions​

[[IF settings.show_apps]]
[[IF settings.show_links]]
<div class="profile-body profile-body--with-links">
[[ELSE]]
<div class="profile-body">
[[/IF]]
[[apps.markup]]
</div>
[[/IF]]

When writing JavaScript in your theme src/index.js, the platform context object contains the user's social links.

After shuuka:contextSnapshot or shuuka:ctx message fires, the context includes:

// Available in your shuuka:ctx message handler
context.links // array of link objects

// Each link object:
{
id: 42,
type: 'instagram',
title: 'Instagram',
url: 'https://www.instagram.com/username',
icon_url: '/social_icons/shuuka-Instagram.png',
active: true
}

Most themes do not need to handle this manually — [[links.markup]] already renders the full links UI. Only use the raw links array if you need custom link rendering that the platform markup does not support.


What Themes Must NOT Do​

WrongWhy
Hardcode profile dataUser data changes; always use [[user.*]]
Style .shk-consent-placeholderPlatform-owned, never override
Add shadows to .billboard-app-containerCreates double-card visual glitch
Use [[...]] syntax inside app template.htmlApp templates use {{...}} only
Skip var(…, fallback) on CSS custom propertiesTheme breaks in Vite dev proxy mode

Next Step​

Read Theme App-Card Integration for the complete card-style broadcast protocol, and Theme Manifest for the full theme.config.json reference.