Vue 3
Chef supports building Vue 3 components. Vue and all its APIs are imported from the Bitrix extension ui.vue3.
Quick Start
Extension Structure
local/js/vendor/my-widget/
├── bundle.config.ts
├── config.php
├── src/
│ ├── index.ts
│ └── components/
│ ├── my-widget.ts
│ └── user-card.ts
└── dist/bundle.config.ts
Standard config — nothing special for Vue:
export default {
input: 'src/index.ts',
output: {
js: 'dist/my-widget.bundle.js',
css: 'dist/my-widget.bundle.css',
},
namespace: 'BX.Vendor.MyWidget',
};Entry Point
// src/index.ts
import { BitrixVue } from 'ui.vue3';
import { MyWidget } from './components/my-widget';
import { UserCard } from './components/user-card';
BitrixVue.component('vendor-my-widget', MyWidget);
BitrixVue.component('vendor-user-card', UserCard);BitrixVue.component() registers the component globally in the Bitrix Vue application. After that it can be used in any Vue app on the page.
Components
Vue components in Bitrix are regular JS/TS files exporting a component object. The template is specified in the template property:
// src/components/user-card.ts
import { Loc } from 'main.core';
// @vue/component
export const UserCard = {
name: 'UserCard',
props: {
userId: {
type: Number,
required: true,
},
name: {
type: String,
required: true,
},
},
emits: ['select'],
computed: {
formattedName(): string
{
return this.name.trim();
},
},
methods: {
handleClick(): void
{
this.$emit('select', this.userId);
},
},
template: `
<div class="user-card" @click="handleClick">
<span class="user-card__name">{{ formattedName }}</span>
</div>
`,
};The // @vue/component comment before the component object helps IDEs (WebStorm, VS Code with Volar) recognize the Vue component and enable autocompletion for template, props, computed and other options.
Nested Components
// src/components/my-widget.ts
import { UserCard } from './user-card';
// @vue/component
export const MyWidget = {
name: 'MyWidget',
components: { UserCard },
data(): { users: Array<{ id: number; name: string }> }
{
return {
users: [],
};
},
methods: {
onUserSelect(userId: number): void
{
console.log('Selected:', userId);
},
},
template: `
<div class="my-widget">
<UserCard
v-for="user in users"
:key="user.id"
:userId="user.id"
:name="user.name"
@select="onUserSelect"
/>
</div>
`,
};Importing Bitrix Extensions
Components use standard imports from Bitrix extensions — dependencies are resolved automatically during build:
import { Type, Loc, Event } from 'main.core';
import { EventEmitter } from 'main.core.events';
import { DateTimeFormat } from 'main.date';Using on a Page
<?php
\Bitrix\Main\UI\Extension::load('vendor.my-widget');
?>
<div id="app">
<vendor-my-widget />
</div>
<script>
BX.Vue3.BitrixVue.createApp({
el: '#app',
});
</script>Production Mode
chef build vendor.my-widget --productionIn production mode the Vue compiler runs with the isProduction flag:
- Dev — components include
__filewith the source path (for Vue Devtools) - Production —
__fileis removed, the bundle is minified, source maps are disabled
Single File Components (SFC)
In addition to the primary approach with JS/TS files, Chef supports building Single File Components — .vue files where template, logic and styles are combined in a single file. Chef automatically detects .vue files in src/ and enables the Vue compiler.
SFC Example
<!-- src/components/Counter.vue -->
<template>
<div class="counter">
<span>{{ count }}</span>
<button @click="increment">+</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Counter',
data(): { count: number }
{
return {
count: 0,
};
},
methods: {
increment(): void
{
this.count++;
},
},
};
</script>
<style>
.counter {
display: flex;
align-items: center;
gap: 8px;
}
</style>Entry Point with SFC
// src/index.ts
import { BitrixVue } from 'ui.vue3';
import Counter from './components/Counter.vue';
BitrixVue.component('ui-counter', Counter);<script lang="ts"> Block
TypeScript in SFC is supported via the lang="ts" attribute:
<script lang="ts">
import { defineComponent, type PropType } from 'ui.vue3';
interface User
{
name: string;
avatar: string;
}
export default defineComponent({
name: 'UserCard',
props: {
user: {
type: Object as PropType<User>,
required: true,
},
},
});
</script><style> Block
Styles from <style> are extracted into the CSS bundle:
<style>
.user-card {
display: flex;
align-items: center;
gap: 12px;
}
</style>Scoped styles
<style scoped> is also supported — Vue will add unique data-v-* attributes for style isolation.
Typing .vue Files
For TypeScript to work correctly with .vue imports, a module declaration is needed. Chef provides it through the ui.dev extension — if tsconfig.json is configured in your project (via chef init build), .vue file typing works out of the box.
If your IDE shows an error on import Component from './Component.vue', make sure:
- You have run
chef init build - Your
tsconfig.jsonincludestypespointing toui.dev
When to Use SFC
SFC are convenient when the template and styles are tightly coupled with the component and it makes sense to keep them together. However, most Bitrix extensions use the approach with JS/TS files and inline template — it's simpler for integration, doesn't require additional type support, and such components are easier to debug.