Skip to content

@tma.js/sdk-vue ​

Vue bindings for @tma.js/sdk. The package turns reactive values of SDK components into Vue refs.

TIP

The package extends @tma.js/sdk, so it is recommended to review the SDK documentation first.

Upgrading from 1.x?

See Migrating from 1.x.

Installation ​

The package requires @tma.js/sdk and vue 3.2 or newer as peer dependencies.

bash
pnpm i @tma.js/sdk @tma.js/sdk-vue
bash
npm i @tma.js/sdk @tma.js/sdk-vue
bash
yarn add @tma.js/sdk @tma.js/sdk-vue

INFO

The package re-exports everything from @tma.js/sdk, so you can import both the SDK and useComputed from @tma.js/sdk-vue. The SDK is a peer dependency, so the application always has a single copy of it: its components are singletons with their own state.

Usage ​

Initialize the SDK and mount the components you use before mounting the application. Then read the components state using useComputed.

ts
import { createApp } from 'vue';
import { init, backButton } from '@tma.js/sdk-vue';

import App from './App.vue';

// Initialize the SDK.
init();

// Mount the Back Button, so it works with its actual state.
backButton.mount();

createApp(App).mount('#app');
vue
<script setup lang="ts">
import { onMounted, onUnmounted, watch } from 'vue';
import { backButton, useComputed } from '@tma.js/sdk-vue';

const isVisible = useComputed(backButton.isVisible);

watch(isVisible, value => {
  console.log('The button is', value ? 'visible' : 'hidden');
});

onMounted(() => {
  backButton.show();
});

onUnmounted(() => {
  backButton.hide();
});
</script>

<template>
  <p>Back button is {{ isVisible ? 'visible' : 'hidden' }}</p>
</template>

useComputed ​

Reactive values of SDK components, like backButton.isVisible or mainButton.state, are computed values (the Computed type). Calling such a value returns its current state, and its subscribe method tracks changes.

useComputed returns a readonly ref updated whenever the computed value changes.

vue
<script setup lang="ts">
import { backButton, mainButton, useComputed } from '@tma.js/sdk-vue';

const isVisible = useComputed(backButton.isVisible);
const mainButtonState = useComputed(mainButton.state);
</script>

<template>
  <p>Back button is {{ isVisible ? 'visible' : 'hidden' }}</p>
  <p>Main button text: {{ mainButtonState.text }}</p>
</template>

The hook accepts only computed values provided by the SDK. To store your own reactive state, use Vue's ref or reactive.

The ref is shallow: objects returned by the SDK are not wrapped into reactive proxies, so they keep their identity. Every change of the computed value replaces the ref value, so watchers of the ref are triggered without the deep option. To change the state, call the component methods, e.g. backButton.show().

Lifetime ​

Inside an effect scope, e.g. a component setup, a composable called from it, or a scope created with effectScope, the subscription is removed when the scope is disposed.

useComputed can also be called outside any effect scope, e.g. in a module scope, to create a ref shared by the whole application. In this case, the subscription is never removed, so avoid calling it this way repeatedly.

ts
import { mainButton, useComputed } from '@tma.js/sdk-vue';

/**
 * Composable encapsulating the Main Button logic.
 */
export function useMainButton() {
  if (!mainButton.isMounted()) {
    mainButton.mount();
  }
  return {
    isVisible: useComputed(mainButton.isVisible),
    text: useComputed(mainButton.text),
  };
}

Vue Router Integration ​

Telegram passes launch parameters to the mini app in the URL hash, see this article for more details.

Therefore, Vue Router should use the HTML5 mode:

ts
import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    // ...
  ],
});

Released under the MIT License.