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.