Development of a decoupled frontend for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    745
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Decoupled Frontend Development for 1C-Bitrix

Decoupled means the frontend is physically separated from Bitrix: it lives on its own server, deploys independently, uses its own stack (React, Vue, Next.js), and communicates with Bitrix only through an API. Unlike a pure headless setup, decoupled can keep some pages on Bitrix templates — for example, the admin panel or CMS-generated pages.

When Decoupled Makes Sense

Decoupled is justified when the existing Bitrix template has become a bottleneck in performance or UX, but a full rewrite is not feasible right now. Typical scenarios:

  • The product catalog is replaced with a React SPA while the rest of the pages stay on Bitrix templates
  • The customer account area is rewritten in Vue while everything else remains unchanged
  • A mobile app pulls data from Bitrix through an API while the website stays on the template

This is an evolutionary approach: you replace parts of the site incrementally, without a full redesign.

The "Island" Pattern — Partial Frontend Integration

Instead of fully separating the frontend, you embed React components into an existing Bitrix template through mount points:

// Inside the Bitrix catalog component template
// /local/templates/main/components/bitrix/catalog/my_template/template.php

// Pass data to React via a data attribute or global variable
$catalogData = json_encode($arResult['ITEMS']);
?>
<div id="react-catalog"
     data-items="<?= htmlspecialchars($catalogData) ?>"
     data-currency="RUB">
</div>

<script src="/local/js/dist/catalog.bundle.js"></script>
<script>
  window.BitrixCatalog && window.BitrixCatalog.mount(
    document.getElementById('react-catalog'),
    <?= $catalogData ?>
  );
</script>
// catalog.bundle.js — built by Webpack/Vite independently
import { createRoot } from 'react-dom/client';
import { CatalogApp } from './CatalogApp';

window.BitrixCatalog = {
    mount(container, initialData) {
        const root = createRoot(container);
        root.render(<CatalogApp initialData={initialData} />);
    }
};

This approach lets you develop the frontend in React with a full toolchain (TypeScript, hot reload, tests) without touching the rest of the Bitrix site.

Build Configuration (Vite)

// vite.config.js for decoupled Bitrix components
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [react()],
    build: {
        outDir: '../public/local/js/dist',
        lib: {
            entry: './src/index.tsx',
            name: 'BitrixComponents',
            formats: ['iife'], // IIFE for embedding in Bitrix templates
            fileName: 'components',
        },
        rollupOptions: {
            external: [], // do not externalize dependencies
        },
    },
    server: {
        cors: true, // allow CORS for the dev server
        port: 3000,
    },
});

In development mode the Vite dev server runs on localhost:3000 while the Bitrix site runs on site.local. API calls from the dev server are proxied through the Vite proxy:

server: {
    proxy: {
        '/api': {
            target: 'http://site.local',
            changeOrigin: true,
        }
    }
}

State Management Between Bitrix and React

The most complex part of decoupled is synchronizing state between the Bitrix part and React components. The cart is the classic example: the cart icon in the Bitrix header must show the correct item count as products are added through the React catalog.

Solution using a custom Event Bus:

// shared/eventBus.js — accessible from both the Bitrix part and React
window.BitrixEventBus = {
    listeners: {},
    emit(event, data) {
        (this.listeners[event] || []).forEach(cb => cb(data));
    },
    on(event, callback) {
        (this.listeners[event] ||= []).push(callback);
    }
};

// In the React component when adding to cart:
window.BitrixEventBus.emit('cart:updated', { count: newCount });

// In the Bitrix template (header):
window.BitrixEventBus.on('cart:updated', ({ count }) => {
    document.querySelector('.cart-counter').textContent = count;
});

Deployment and CI/CD

A decoupled frontend requires a dedicated build step in CI/CD. A simple GitLab CI pipeline:

build-frontend:
  stage: build
  script:
    - cd frontend
    - npm ci
    - npm run build
    - rsync -avz dist/ server:/var/www/site/local/js/dist/
  only:
    - main

After deploying the frontend, Bitrix templates automatically pick up the new bundle version. Version your files by content hash (catalog.a1b2c3.js) to avoid browser caching issues.

Decoupled is a sensible compromise between "rewrite everything" and "leave it as is." It lets you modernize the frontend incrementally, reduces risk, and gives you a realistic measure of ROI from the new stack before committing to a full migration.