PHPackages                             combat-ui/core-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. combat-ui/core-bundle

ActiveSymfony-bundle[Utility &amp; Helpers](/categories/utility)

combat-ui/core-bundle
=====================

A bundle containing UI elements usable in Symfony that use the Combat UI framework

0.6.4(1mo ago)041↓74.5%2MITPHP ~8.3.0 ||~8.4.0 || ~8.5.0

Since Jul 6Compare

[ Source](https://github.com/Combat-Marketing/combat-ui-symfony-bundle)[ Packagist](https://packagist.org/packages/combat-ui/core-bundle)[ RSS](/packages/combat-ui-core-bundle/feed)WikiDiscussions Synced 1w ago

READMEChangelog (5)Dependencies (32)Versions (7)Used By (2)

Combat UI Core Bundle
=====================

[](#combat-ui-core-bundle)

[![Tests](https://github.com/Combat-Marketing/combat-ui-symfony-bundle/actions/workflows/tests.yml/badge.svg)](https://github.com/Combat-Marketing/combat-ui-symfony-bundle/actions/workflows/tests.yml)[![PHP](https://camo.githubusercontent.com/4d97c2be3487245109f5e3987c0ac94269a4c8d834e62abfe51a3ea191dee3d5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e34253230253743253230382e352d373737626233)](https://camo.githubusercontent.com/4d97c2be3487245109f5e3987c0ac94269a4c8d834e62abfe51a3ea191dee3d5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e34253230253743253230382e352d373737626233)[![Symfony](https://camo.githubusercontent.com/d8ae3a5511134cb8368c4959d2cd8005f66a032ce1077c3a28434a95efd34178/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796d666f6e792d372e34253230253743253230382e782d303030303030)](https://camo.githubusercontent.com/d8ae3a5511134cb8368c4959d2cd8005f66a032ce1077c3a28434a95efd34178/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796d666f6e792d372e34253230253743253230382e782d303030303030)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)

The official Symfony integration for [Combat UI](https://github.com/Combat-Marketing/combat-ui) — a lightweight, themeable front-end framework built on custom elements (``, ``, ``, …) and a utility-free CSS layer.

This bundle turns the framework into first-class Twig building blocks:

```
{% cui 'hero' with { eyebrow: 'New', title: 'Ship faster', lead: 'Combat UI in Twig.' } %}
    {% cui_slot 'actions' %}
        {% cui 'button' with { variant: 'primary', href: '/docs' } %}Read the docs{% endcui %}
    {% endcui_slot %}
    {% cui_slot 'media' %}{% endcui_slot %}
{% endcui %}
```

It is deliberately CMS-agnostic: it only needs Twig and Webpack Encore. CMS-specific integrations (such as the OpenDXP bundle) are thin wrappers on top of this one.

What you get
------------

[](#what-you-get)

- **A `{% cui %}` Twig tag** — render any Combat UI component, section, or layout by name, pass props with `with {…}`, and fill slots with the tag body and nested `{% cui_slot %}` tags.
- **A `cui_component()` function** — the same renderer in expression form, handy for one-liners and dynamic component names.
- **A curated template library** — 25+ ready-made Twig templates for components (cards, forms, modal, navbar, pagination, tabs, …), page sections (hero, CTA, page intro), and every-layout-style layout primitives (stack, cluster, grid, sidebar, switcher, cover, …). All of them overridable per-app via Symfony's standard bundle template override.
- **Generic element rendering** — any Combat UI custom element without a curated template still renders as a proper `` tag with props mapped to attributes.
- **`cui_attrs()`** — a safe, expressive HTML attribute renderer (boolean attributes, conditional class lists, style maps, `data-*` expansion, full escaping).
- **`cui_assets()`** — one function that outputs the framework's CSS/JS tags from a prebuilt Webpack Encore build that ships with the bundle. Zero front-end tooling required to get started.
- **`cui_theme_script()`** — a tiny inline script that restores the visitor's light/dark preference before first paint, preventing theme flash.
- **Configurable component defaults** — set project-wide default props per component in YAML.

Requirements
------------

[](#requirements)

DependencyVersionPHP8.4 or 8.5Symfony7.4 or 8.xTwig^3.21symfony/webpack-encore-bundle^2.1Installation
------------

[](#installation)

```
composer require combat-ui/core-bundle
```

Register the bundle if you don't use Flex auto-registration:

```
// config/bundles.php
return [
    // ...
    CombatUI\Bundle\CoreBundle\CombatUICoreBundle::class => ['all' => true],
];
```

Publish the prebuilt assets:

```
php bin/console assets:install
```

Then load the framework in your base layout:

```
{# templates/base.html.twig #}

        {{ cui_assets() }}

    ...

```

That's it — the bundle automatically registers a `combat_ui` Encore build pointing at its prebuilt assets (installed to `public/bundles/combatuicore/build`), so `cui_assets()` works out of the box without touching your own Encore setup.

Usage
-----

[](#usage)

### The `{% cui %}` tag

[](#the--cui--tag)

Render a component by name. Props go in a `with` map; the tag body becomes the component's **default slot**:

```
{% cui 'button' with { variant: 'primary', href: '/signup' } %}
    Sign up
{% endcui %}
```

Named slots are filled with the nested `{% cui_slot %}` tag:

```
{% cui 'hero' with { title: 'Launch' } %}
    {% cui_slot 'media' %}{% endcui_slot %}
    Everything outside a cui_slot lands in the default slot.
{% endcui %}
```

### The `cui_component()` function

[](#the-cui_component-function)

The same renderer as an expression. A plain string as the third argument is escaped and used as the default slot:

```
{{ cui_component('button', { variant: 'primary' }, 'Click me') }}
{{ cui_component(card_type ~ '-card', item.props) }}
```

### How names resolve

[](#how-names-resolve)

`{% cui 'name' %}` resolves the name in this order — first match wins:

1. `@CombatUICore/components/.html.twig` — curated component wrappers
2. `@CombatUICore/sections/.html.twig` — page sections
3. `@CombatUICore/layouts/.html.twig` — layout primitives
4. A **generic `` element**, if the name is a known Combat UI custom element — props become HTML attributes (`snake_case` → `kebab-case`), extras can be added via the `attr` prop.

An unknown name throws a clear `RuntimeError` listing the known elements. The `cui-` prefix is optional: `'cui-button'` and `'button'` are equivalent.

Because resolution goes through the `@CombatUICore` Twig namespace, **any shipped template can be overridden** the standard Symfony way — drop your version in:

```
templates/bundles/CombatUICoreBundle/components/button.html.twig

```

### What's in the box

[](#whats-in-the-box)

**Components** (`templates/components/`)

`article-card`, `article-filter`, `button`, `case-card`, `contact-card`, `contact-methods`, `content-card`, `disclosure`, `event-card`, `feature-card`, `field`, `figure`, `form`, `itinerary-item`, `location-card`, `logo-item`, `media-card`, `media-full`, `media-overlay`, `modal`, `navbar`, `org-chart`, `pagination`, `person`, `stat`, `tabs`, `vacancy-card`

**Sections** (`templates/sections/`)

`hero`, `cta`, `page-intro`, `section`

**Layouts** (`templates/layouts/`) — composable primitives in the spirit of *Every Layout*:

`stack`, `cluster`, `grid`, `sidebar`, `split`, `switcher`, `center`, `cover`, `frame`, `container`, `prose`

```
{% cui 'stack' with { gap: 'var(--cui-space-l)' } %}
    {% cui 'grid' with { min: '18rem' } %}
        {% for item in items %}
            {% cui 'content-card' with item.props %}{% endcui %}
        {% endfor %}
    {% endcui %}
{% endcui %}
```

**Generic custom elements** — rendered without a curated wrapper:

`calendar`, `carousel`, `code`, `cookie-banner`, `day-planner`, `map`, `reveal`, `scroll-stage`, `sidenav`, `theme-toggle`, `toast-region`, `tree`

Each shipped template documents its props and slots in a comment at the top of the file — that's the per-component reference.

### `cui_attrs()` — HTML attribute rendering

[](#cui_attrs--html-attribute-rendering)

Used throughout the shipped templates and available for your own:

```

```

Values are HTML-escaped, and invalid attribute names throw instead of rendering — so props can never smuggle markup into your attributes.

### Assets and theming

[](#assets-and-theming)

`cui_assets()` renders the `` and `` tags for the Combat UI build, prefixed (by default) with the theme-restore script:

```
{{ cui_assets() }}                        {# default build & entry #}
{{ cui_assets('my-entry', 'my_build') }}  {# explicit entry / Encore build #}
```

`cui_theme_script()` is also available standalone. It reads `cui-theme` from `localStorage` and sets `data-theme` on `` synchronously, so a returning dark-mode visitor never sees a light flash.

### Component defaults

[](#component-defaults)

Set project-wide default props per component; explicit props in the template always win:

```
# config/packages/combat_ui_core.yaml
combat_ui_core:
    component_defaults:
        button:
            variant: primary
        hero:
            align: center
```

Configuration reference
-----------------------

[](#configuration-reference)

```
combat_ui_core:
    # Webpack Encore integration used by cui_assets()
    encore:
        # Name of the Encore build cui_assets() reads from.
        # 'combat_ui' (the default) is auto-registered by the bundle;
        # set a different name to take over asset building yourself.
        build_name: combat_ui

        # Entry point rendered by cui_assets()
        entry: combat-ui

        # Directory containing the build's entrypoints.json.
        # Defaults to where assets:install puts the bundle's prebuilt assets.
        build_path: '%kernel.project_dir%/public/bundles/combatuicore/build'

    # Prefix cui_assets() output with the theme-restore script
    theme_guard: true

    # Default props merged into every render of the given component
    component_defaults: {}
```

### Bringing your own build

[](#bringing-your-own-build)

The prebuilt assets are great for getting started, but for tree-shaking or bundling Combat UI with your own front-end code you can point the bundle at your own Encore build:

1. Add `@combat-ui/core` to your app's `package.json` and create an entry that imports it.
2. Register that build in `webpack_encore.builds` (or reuse your default build).
3. Point the bundle at it:

```
combat_ui_core:
    encore:
        build_name: app   # the bundle stops auto-registering its own build
        entry: app
```

Testing &amp; quality
---------------------

[](#testing--quality)

```
vendor/bin/codecept build   # generate actor classes
vendor/bin/codecept run     # run the Codeception suites
vendor/bin/phpstan          # static analysis
```

CI runs the suites against PHP 8.4/8.5 × Symfony 7.4/8.x.

Related packages
----------------

[](#related-packages)

- [`@combat-ui/core`](https://www.npmjs.com/package/@combat-ui/core) — the underlying front-end framework (custom elements + CSS)
- **Combat UI OpenDXP Bundle** — CMS integration for OpenDXP, built on top of this bundle

License
-------

[](#license)

Released under the [MIT License](LICENSE).

Copyright © 2026 [Combat Jongerenmarketing en -communicatie B.V.](https://www.combat.nl)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance93

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

6

Last Release

37d ago

PHP version history (2 changes)v0.6.0PHP ~8.4.0 || ~8.5.0

0.6.4PHP ~8.3.0 ||~8.4.0 || ~8.5.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/682256?v=4)[Christiaan van Dam](/maintainers/h4rdc0m)[@h4rdc0m](https://github.com/h4rdc0m)

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/combat-ui-core-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/combat-ui-core-bundle/health.svg)](https://phpackages.com/packages/combat-ui-core-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M431](/packages/easycorp-easyadmin-bundle)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.8M683](/packages/shopware-core)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

9626.1k75](/packages/open-dxp-opendxp)[chameleon-system/chameleon-base

The Chameleon System core.

1029.4k6](/packages/chameleon-system-chameleon-base)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
