Bitrix24 UI Kit (@bitrix24/b24ui-nuxt) — это UI-библиотека для разработки веб-приложений через REST API Bitrix24 на базе Nuxt и Vue. Библиотека предоставляет готовые компоненты, повторяющие дизайн Bitrix24, что позволяет разработчикам быстро создавать красивые и консистентные приложения.
Проект УЖЕ содержит необходимую базовую структуру и настройки для frontend на базе Nuxt с интеграцией Bitrix24 UI Kit. При добавлении функционала нужно придерживаться этой структуры и использовать компоненты из @bitrix24/b24ui-nuxt.
Актуальная структура проекта:
frontend/
├── app/
│ ├── app.config.ts # Конфигурация B24UI
│ ├── app.vue # Корневой компонент
│ ├── assets/css/main.css # Главный CSS файл
│ ├── components/ # Компоненты приложения
│ │ ├── BackendStatus.vue
│ │ └── Logo.vue
│ ├── composables/ # Переиспользуемая логика
│ ├── pages/ # Страницы Nuxt
│ │ ├── index.client.vue
│ │ ├── install.client.vue
│ │ ├── handler/
│ │ └── slider/
│ └── stores/ # Pinia stores
├── nuxt.config.ts # Конфигурация Nuxt
├── package.json # Зависимости
└── i18n/ # Интернационализация
├── locales/
└── i18n.map.ts
Ключевые особенности:
- Основан на Nuxt UI, но адаптирован под дизайн-систему Bitrix24
- Использует Tailwind CSS 4 и Tailwind Variants для стилизации
- Поддерживает Nuxt 4+ и Vue 3 + Vite
- Включает 80+ компонентов и composables
- Интегрируется с
@bitrix24/b24icons-vue(1400+ иконок)
Важно: Всегда используйте компоненты именно из @bitrix24/b24ui-nuxt, а НЕ из Nuxt UI!
nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@bitrix24/b24ui-nuxt']
})assets/css/main.css:
@import "tailwindcss";
@import "@bitrix24/b24ui-nuxt";app.vue:
<template>
<B24App :locale="locales[locale]">
<NuxtLoadingIndicator color="var(--ui-color-design-filled-warning-bg)" :height="3" />
<B24DashboardGroup>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</B24DashboardGroup>
</B24App>
</template>Оборачивайте приложение в <B24App> для корректной работы Toast, Tooltip, Modal и программных оверлеев:
<template>
<B24App>
<!-- ваш контент -->
</B24App>
</template>Все компоненты используют префикс B24:
<B24Button>,<B24Input>,<B24Modal>,<B24Form>и т.д.
Иконки импортируются из @bitrix24/b24icons-vue:
<script setup>
import RocketIcon from '@bitrix24/b24icons-vue/main/RocketIcon'
</script>
<template>
<B24Button :icon="RocketIcon" label="Запуск" />
</template>📖 Полный список иконок
📖 Метаданные иконок
📖 Интеграция иконок
Приложение в базовом виде содержит примеры реализации некоторых страниц в папке pages/:
- index.client.vue — главная страница приложения
- install.client.vue — страница установки приложения
- slider/app-options.client.vue — страница настроек приложения в слайдере
- handler/placement-crm-deal-detail-tab.client.vue — пример страницы для встройки в карточку сделки
- handler/uf.demo.client.vue — пример страницы для встройки пользовательского типа поля
- handler/background-some-problem-client.vue - пример страницы об ошибке
Важно: все страницы выполняются ТОЛЬКО на клиенте, поскольку frontend будет собираться в виде статики для показа внутри фрейма Bitrix24. Поэтому все файлы страниц имеют суффикс .client.vue.
При создании новых страниц подбирай подходящий шаблон из layouts/ для консистентного внешнего вида. Обычно используется default.vue, который уже содержит B24SidebarLayout.
- placement.vue — для страниц реализующих виджеты;
- slider.vue - для страниц реализующих слайдеры, открывающиеся вне текущего iframe интерфейса приложения;
- uf-placement.vue - для страниц реализующих встройку пользовательских типов полей. Подробности про этот тип встройки виджетов.
Компоненты поддерживают два способа кастомизации:
Через b24ui prop (для слотов внутри компонента):
<B24Button
:b24ui="{
baseLine: 'justify-center',
leadingIcon: 'text-red-500'
}"
/>Через class prop (для корневого элемента):
<B24Button class="font-bold rounded-full" />Старайтесь избегать глобальных CSS переопределений, чтобы не нарушить дизайн-систему, а также избегайте лишних стилей оформления без необходимости - компоненты по умолчанию уже стилизованы согласно гайдлайнам Bitrix24.
Компоненты используют систему вариантов. Основные параметры:
color: air-primary, air-secondary-no-accent, air-primary-success, air-primary-alert, air-primary-warning, air-primary-copilot, air-secondary-accent, air-tertiary и др.
size: xss, xs, sm, md, lg, xl (зависит от компонента)
Пример:
<B24Button
color="air-primary"
size="md"
rounded
loading-auto
/>Для реализации пользовательских сценариев в интерфейсе необходимо ориентироваться на заготовки в файлах accordion.md, calendar.md, form.md, selector.md, settings-page.md, table-and-grid.md. Если нужный сценарий этими заготовками реализовать нельзя, следует использовать компоненты из этого раздела.
B24Button — основная кнопка
📖 Исходный код
📖 Theme
<B24Button
label="Сохранить"
color="air-primary"
size="md"
:icon="SaveIcon"
loading-auto
@click="handleSave"
/>B24FieldGroup — группа кнопок
📖 Исходный код
📖 Theme
B24Input — текстовый инпут
📖 Исходный код
📖 Theme
<B24Input
v-model.trim="email"
type="email"
placeholder="Email"
color="air-primary"
size="md"
/>B24Textarea — многострочный ввод
📖 Исходный код
📖 Theme
B24Select — выпадающий список
📖 Исходный код
📖 Theme
<B24Select
v-model="selected"
:items="[
{ label: 'Опция 1', value: '1' },
{ label: 'Опция 2', value: '2' }
]"
placeholder="Выберите..."
/>B24Checkbox — чекбокс
📖 Исходный код
📖 Theme
B24RadioGroup — группа радио-кнопок
📖 Исходный код
📖 Theme
B24Switch — переключатель
📖 Исходный код
📖 Theme
B24Form + B24FormField — форма с валидацией (Zod, Valibot, Yup и др.)
📖 Исходный код Form
📖 Исходный код FormField
📖 Theme Form
📖 Theme FormField
📖 Документация
<B24Form :state="state" :schema="schema" @submit="onSubmit">
<B24FormField name="email" label="Email" required>
<B24Input v-model="state.email" type="email" />
</B24FormField>
<B24Button type="submit" color="air-primary" loading-auto>
Отправить
</B24Button>
</B24Form>B24Modal — модальное окно
📖 Исходный код
📖 Theme
📖 Документация
<B24Modal title="Заголовок" description="Описание">
<B24Button label="Открыть" />
<template #body>
<p>Содержимое модалки</p>
</template>
<template #footer="{ close }">
<B24Button color="air-primary" @click="save">Сохранить</B24Button>
<B24Button color="air-tertiary" @click="close">Отмена</B24Button>
</template>
</B24Modal>B24Slideover — боковая панель
📖 Исходный код
📖 Theme
B24Toast — уведомления (обычно через useToast())
📖 Исходный код
📖 Theme
B24Tooltip — всплывающие подсказки
📖 Исходный код
📖 Theme
B24Popover — всплывающий контейнер
📖 Исходный код
📖 Theme
B24NavigationMenu — навигационное меню
📖 Исходный код
📖 Theme
B24DropdownMenu — выпадающее меню
📖 Исходный код
📖 Theme
B24Tabs — вкладки
📖 Исходный код
📖 Theme
B24Breadcrumb — хлебные крошки
📖 Исходный код
📖 Theme
B24SidebarLayout — основной layout с боковой панелью
📖 Исходный код
📖 Theme
Этот компонент УЖЕ используется в качестве основы базовой страницы в шаблоне layouts/defeult.vue проекта. Если страница приложения создается на базе этого шаблона, НЕЛЬЗЯ использовать B24SidebarLayout внутри страницы повторно.
Правила размещения контента в B24SidebarLayout
- Компоненты страницы рендерятся внутри
<slot>компонентаB24SidebarLayoutчерез активныйlayout. - Размещайте контент непосредственно в
slot— без дополнительных обёрток для центрирования (flex items-center justify-center,min-h-screen,min-h-dvh,max-w-*контейнеры). - Layout уже обеспечивает корректные отступы, фон и поведение прокрутки.
- Используйте
B24Card(или другие компоненты B24) напрямую как корневой элемент шаблона страницы. - Для состояний загрузки используйте
B24Skeletonвместо скрытия всей страницы. - ❌ Неправильно:
<div class="flex items-center justify-center min-h-screen"><B24Card class="max-w-md">…</B24Card></div> - ✅ Правильно:
<B24Card>…</B24Card>(или<div class="flex flex-col gap-4 p-6"><B24Card>…</B24Card></div>для страниц с несколькими карточками)
Связанные компоненты:
- B24Sidebar — исходный код
- B24SidebarHeader — исходный код
- B24SidebarBody — исходный код
- B24SidebarFooter — исходный код
- B24Navbar — исходный код
B24Avatar / B24AvatarGroup — аватары
📖 Avatar: исходный код / theme
📖 AvatarGroup: исходный код / theme
B24Badge — бейджи
📖 Исходный код
📖 Theme
B24Chip — числовые метки
📖 Исходный код
📖 Theme
B24Card — карточка
📖 Исходный код
📖 Theme
B24Alert / B24Advice — предупреждения и советы
📖 Alert: исходный код / theme
📖 Advice: исходный код / theme
B24Table / B24TableWrapper — таблицы
📖 Table: исходный код / theme
📖 TableWrapper: исходный код / theme
B24DescriptionList — список описаний
📖 Исходный код
📖 Theme
B24Skeleton — skeleton loader
📖 Исходный код
📖 Theme
B24Empty — пустое состояние
📖 Исходный код
📖 Theme
B24Progress — прогресс-бар
📖 Исходный код
📖 Theme
B24Range — слайдер
📖 Исходный код
📖 Theme
B24Calendar — календарь
📖 Исходный код
📖 Theme
B24Countdown — таймер обратного отсчета
📖 Исходный код
📖 Theme
B24Accordion / B24Collapsible — раскрывающиеся блоки
📖 Accordion: исходный код / theme
📖 Collapsible: исходный код / theme
B24Separator — разделитель
📖 Исходный код
📖 Theme
B24Kbd — клавиша клавиатуры
📖 Исходный код
📖 Theme
Управление уведомлениями.
const toast = useToast()
// Добавить уведомление
toast.add({
title: 'Успех',
description: 'Данные сохранены',
color: 'air-primary-success'
})
// Обновить
toast.update(id, { title: 'Обновлено' })
// Удалить
toast.remove(id)
// Очистить все
toast.clear()Программное управление модальными окнами и slideоvers.
const overlay = useOverlay()
// Создать экземпляр
const modal = overlay.create(MyModalComponent, {
props: { title: 'Заголовок' },
destroyOnClose: true
})
// Открыть и получить результат
const opened = modal.open({ additionalProp: 'value' })
const result = await opened.result // ждет emit('close', payload)
// Закрыть
modal.close(resultValue)
// Обновить props на лету
modal.patch({ title: 'Новый заголовок' })Регистрация глобальных горячих клавиш.
defineShortcuts({
'meta_k': () => openCommandPalette(),
'escape': () => closeAllOverlays(),
'ctrl_s': (e) => { e.preventDefault(); save() }
})Интернационализация.
📖 useLocale: исходный код
📖 defineLocale: исходный код
Конфетти-анимация.
const confetti = useConfetti()
confetti.fire()Интеграция с формой для кастомных компонентов.
Убедитесь, что:
@bitrix24/b24ui-nuxtустановлен- Модуль добавлен в
nuxt.config.ts - CSS импортирован
- Приложение обернуто в
<B24App>
-
Найдите исходный код компонента в GitHub:
- Перейдите в src/runtime/components/
- Откройте нужный компонент (например,
Button.vue) - Изучите
Props,Slots,Emits
-
Проверьте theme компонента:
- Перейдите в src/theme/
- Откройте файл темы (например,
button.ts) - Проверьте доступные
variants,slots,defaultVariants
-
Изучите документацию (если есть):
{
"dependencies": {
"@bitrix24/b24ui-nuxt": "^2.0.0",
"@bitrix24/b24icons-vue": "^2.0.0",
"nuxt": "^4.0.0",
"vue": "^3.0.0"
}
}Проблема: Компоненты не рендерятся
Решение: Проверьте наличие <B24App> в корне приложения
Проблема: Toast/Tooltip/Modal не работают
Решение: Убедитесь, что используется <B24App> (предоставляет OverlayProvider)
Проблема: Иконки не отображаются
Решение: Проверьте правильность импорта из @bitrix24/b24icons-vue/category/IconName
Проблема: Стили не применяются
Решение: Убедитесь, что CSS импортирован (@import "@bitrix24/b24ui-nuxt")
Проблема: TypeScript ошибки
Решение: Проверьте типы в исходниках компонента или theme файле
- Исходный код модуля: src/module.ts
- Все компоненты: src/runtime/components/
- Все composables: src/runtime/composables/
- Все темы: src/theme/
- Примеры использования: playgrounds/demo/app/
- Тесты компонентов: test/components/
- 📚 Официальная документация
- 🎨 Иконки Bitrix24
- 💾 GitHub репозиторий
- 🎮 Demo приложение
- 🚀 Starter template
- 📖 README для ИИ (расширенный)
- Всегда используйте B24 префикс — это компоненты Bitrix24 UI, а не Nuxt UI
- Оборачивайте в B24App — обязательно для работы оверлеев и уведомлений
- Используйте b24ui prop — для точной кастомизации слотов компонента
- Следуйте дизайн-системе — используйте предустановленные цвета (
air-*) и размеры - Проверяйте theme — для понимания доступных вариантов и слотов
- Изучайте исходники — они хорошо документированы и содержат TypeScript типы
В проекте используется Pinia для управления состоянием. Создавайте stores в папке composables/ или stores/ используя Composition API:
// composables/useDeals.ts
export const useDealsStore = defineStore('deals', () => {
// Состояние
const deals = ref<Deal[]>([]);
const currentDeal = ref<Deal | null>(null);
const isLoading = ref(false);
const error = ref<string | null>(null);
// Фильтры
const filters = ref<DealFilters>({
stage: null,
search: '',
dateFrom: null,
dateTo: null
});
// Геттеры
const filteredDeals = computed(() => {
let result = deals.value;
if (filters.value.stage) {
result = result.filter(deal => deal.stageId === filters.value.stage);
}
if (filters.value.search) {
const search = filters.value.search.toLowerCase();
result = result.filter(deal =>
deal.title.toLowerCase().includes(search)
);
}
return result;
});
// Действия
async function fetchDeals() {
isLoading.value = true;
error.value = null;
try {
const { data } = await $fetch<{data: Deal[]}>('/api/deals');
deals.value = data;
} catch (err) {
error.value = err instanceof Error ? err.message : 'Failed to fetch deals';
} finally {
isLoading.value = false;
}
}
return {
// State
deals: readonly(deals),
currentDeal: readonly(currentDeal),
isLoading: readonly(isLoading),
error: readonly(error),
filters,
// Getters
filteredDeals,
// Actions
fetchDeals
};
});// composables/useApi.ts
export function useApi() {
const isLoading = ref(false);
const error = ref<string | null>(null);
async function apiCall<T>(
url: string,
options?: RequestInit
): Promise<T | null> {
isLoading.value = true;
error.value = null;
try {
const response = await $fetch<T>(url, options);
return response;
} catch (err) {
error.value = err instanceof Error ? err.message : 'API call failed';
return null;
} finally {
isLoading.value = false;
}
}
return {
isLoading: readonly(isLoading),
error: readonly(error),
apiCall
};
}Проект использует Tailwind CSS 4 через Vite плагин, что отличается от классической конфигурации:
nuxt.config.ts:
import tailwindcss from '@tailwindcss/vite'
export default defineNuxtConfig({
vite: {
plugins: [tailwindcss()]
}
})assets/css/main.css:
@import "tailwindcss";
@import "@bitrix24/b24ui-nuxt";
@theme static {
/* Кастомные утилиты здесь */
}@theme {
--color-primary-50: theme(colors.blue.50);
--color-primary-500: theme(colors.blue.500);
--color-primary-900: theme(colors.blue.900);
--font-family-brand: ui-serif, serif;
--spacing-18: 4.5rem;
}<!-- Адаптивная сетка -->
<template>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<!-- Карточки -->
<B24Card
v-for="item in items"
:key="item.id"
class="p-4"
>
{{ item.title }}
</B24Card>
</div>
</template><!-- components/MobileNavigation.vue -->
<template>
<div class="lg:hidden">
<!-- Мобильное меню -->
<B24Button
variant="ghost"
@click="isOpen = !isOpen"
>
<B24Icon name="bars-3" />
</B24Button>
<!-- Выдвижная панель -->
<B24Slideover v-model="isOpen" side="left">
<B24Card class="p-4">
<nav class="space-y-2">
<NuxtLink
v-for="item in navigation"
:key="item.to"
:to="item.to"
class="block px-4 py-2 rounded-lg hover:bg-gray-100"
@click="isOpen = false"
>
{{ item.label }}
</NuxtLink>
</nav>
</B24Card>
</B24Slideover>
</div>
</template><script setup>
// Ленивая загрузка тяжелых компонентов
const LazyChart = defineAsyncComponent(() => import('~/components/Chart.vue'));
const LazyDataTable = defineAsyncComponent(() => import('~/components/DataTable.vue'));
const showChart = ref(false);
</script>
<template>
<div>
<!-- Основной контент загружается сразу -->
<B24Card class="mb-4">
<B24Button @click="showChart = true" v-if="!showChart">
Показать график
</B24Button>
</B24Card>
<!-- Тяжелые компоненты загружаются по требованию -->
<LazyChart v-if="showChart" :data="chartData" />
</div>
</template><!-- components/DealList.vue -->
<template>
<B24Container class="py-8">
<!-- Заголовок и действия -->
<div class="mb-6 flex items-center justify-between">
<h1 class="text-2xl font-bold">Сделки</h1>
<B24Button @click="openCreateModal">
Создать сделку
</B24Button>
</div>
<!-- Фильтры -->
<B24Card class="mb-6 p-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<B24Select
v-model="filters.stage"
:options="stageOptions"
placeholder="Выберите стадию"
/>
<B24Input
v-model="filters.search"
placeholder="Поиск по названию"
>
<template #leading>
<B24Icon name="magnifying-glass" />
</template>
</B24Input>
<B24Button
variant="outline"
@click="clearFilters"
>
Очистить фильтры
</B24Button>
</div>
</B24Card>
<!-- Таблица -->
<B24Card>
<B24Table
:columns="columns"
:rows="filteredDeals"
:loading="isLoading"
>
<template #actions="{ row }">
<div class="flex gap-2">
<B24Button size="sm" @click="editDeal(row.id)">
Редактировать
</B24Button>
<B24Button
size="sm"
color="red"
variant="outline"
@click="deleteDeal(row.id)"
>
Удалить
</B24Button>
</div>
</template>
</B24Table>
</B24Card>
</B24Container>
</template>// utils/formatters.ts
export const formatters = {
// Форматирование валюты
currency(amount: number, currency: string = 'RUB'): string {
return new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: currency,
minimumFractionDigits: 0,
maximumFractionDigits: 2
}).format(amount);
},
// Форматирование даты
date(date: string | Date, format: 'short' | 'long' = 'short'): string {
const d = typeof date === 'string' ? new Date(date) : date;
if (format === 'short') {
return d.toLocaleDateString('ru-RU');
}
return d.toLocaleDateString('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
},
// Относительное время
timeAgo(date: string | Date): string {
const d = typeof date === 'string' ? new Date(date) : date;
const now = new Date();
const diff = now.getTime() - d.getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) return 'только что';
if (minutes < 60) return `${minutes} мин. назад`;
if (hours < 24) return `${hours} ч. назад`;
if (days < 7) return `${days} дн. назад`;
return d.toLocaleDateString('ru-RU');
},
// Сокращение текста
truncate(text: string, length: number = 100): string {
if (text.length <= length) return text;
return text.slice(0, length) + '...';
}
};- Используйте B24 компоненты вместо нативных HTML элементов
- Разделяйте презентационные и контейнерные компоненты
- Создавайте переиспользуемые композиции из B24UI компонентов
- Документируйте API компонентов через props и emits
- Локальное состояние для UI логики компонента
- Pinia Store для глобального состояния приложения
- Composables для переиспользуемой логики
- Избегайте prop drilling, используйте provide/inject
- Ленивая загрузка компонентов и маршрутов
- Виртуализация для больших списков (через B24Table)
- Мемоизация вычислений через computed
- Дебаунс для пользовательского ввода
- B24UI уже включает ARIA атрибуты
- Семантические компоненты (B24Card, B24Table)
- Клавиатурная навигация работает из коробки
- Контрастность цветов соответствует дизайн-системе
Версия: 2.1.0
Последнее обновление: Ноябрь 2025
Лицензия: MIT