---
name: ui-bundle
description: >
  Use webedia/ui-bundle Twig templates, SCSS, and JavaScript in Symfony projects.
  Trigger when the developer asks to: add/use a UI component (button, label, thumbnail, card, header, footer, breadcrumb, pagination, roller/carousel, player, search, etc.),
  import SCSS styles from @Ui, import JS modules from @Ui, integrate the UI bundle in their project,
  use Twig macros or includes from @Ui namespace, theme or customize UI bundle variables,
  or asks "how do I use [component]" from the bundle.
  Also trigger when working in a Symfony project that has webedia/ui-bundle in vendor/.
---

# webedia/ui-bundle

Symfony bundle providing Twig templates, SCSS, and JS for Webedia frontend projects.

- **Storybook**: https://webediagroup.gitlab.io/transverse/shared/ui-bundle/mr-292/
- **Vendor path**: `vendor/webedia/ui-bundle/`
- **Docs in vendor**: `vendor/webedia/ui-bundle/docs/` (TWIG_TEMPLATES_GUIDE.md, SCSS_GUIDE.md, JS_GUIDE.md)

## The @Ui Alias

The `@Ui` alias resolves to **different paths** depending on context:

| Context | @Ui resolves to |
|---------|----------------|
| **Twig** (`{% include %}`, `{% from %}`) | `vendor/webedia/ui-bundle/templates/` |
| **Webpack** (SCSS `@import`, JS `import`) | `vendor/webedia/ui-bundle/assets/` |

Webpack alias config (in `webpack.config.js`):
```js
.addAliases({
    '@Ui': path.resolve(__dirname, './vendor/webedia/ui-bundle/assets'),
})
```

## Template Hierarchy

Three tiers in `templates/`:

| Tier | Location | Pattern | Count |
|------|----------|---------|-------|
| **Components** | `component/` | Macro OR include | 8 |
| **Modules** | `module/` | Include with `only` | 43 |
| **Sections** | `section/` | Extends + blocks | 6 |

Dependencies: Sections > Modules > Components (never reverse).

## How to Look Up a Component

1. Check the catalogs in this skill's `references/` folder to find the right template
2. Read the actual template from `vendor/webedia/ui-bundle/templates/` to confirm current args
3. Optionally read the `.stories.ts` file nearby for typed arg documentation
4. For SCSS variables, read `vendor/webedia/ui-bundle/assets/scss/config/default_variables.scss`

## Import Patterns

### Pattern A: Macro Components

4 components use macros: **button**, **label**, **thumbnail**, **data_attributes**.

```twig
{% from "@Ui/component/button.html.twig" import button %}
{{ button({ text: 'Click me', size: 'lg', href: '/path' }) }}
```

- Import with `{% from %}`, call as function
- Pass a **single config object** parameter
- Macro name may differ from filename (e.g., `thumbnail.html.twig` exports `thumb()`, not `thumbnail()`)

| File | Macro name | Param name |
|------|-----------|------------|
| `button.html.twig` | `button` | `button_obj` |
| `label.html.twig` | `label` | `obj` |
| `thumbnail.html.twig` | `thumb` | `obj` |
| `data_attributes.html.twig` | `dataAttributes` | `data_attributes_obj` |

### Pattern B: Include Components & Modules

4 components (`title`, `subtitle`, `share`, `cta_subcategory`) + all 43 modules use includes.

```twig
{% include "@Ui/module/article/article_title.html.twig" with {
    article_title: 'My Article',
    label: [{ value: 'News', type: 'category' }],
    published_date: '2024-01-15'
} only %}
```

- Variables are top-level (NOT wrapped in an object)
- **ALWAYS use `only`** to prevent variable leakage
- Each variable uses `|default()` in the template

### Pattern C: Sections (Extends)

```twig
{% embed "@Ui/section/dynamic_content/layout_2_cols_ads.html.twig" with {
    title_text: 'Latest News',
    entities: articles
} %}
    {% block item %}
        {# render each entity #}
    {% endblock %}
{% endembed %}
```

## SCSS Integration

**CRITICAL**: Import order matters. `default_variables.scss` uses `global-variable-exists()` so project theme vars MUST come before it.

```scss
@use "sass:math";

// 1. Project theme declarations (defines vars BEFORE bundle reads them)
@import 'project_theme_config';

// 2. Bundle defaults (conditionally uses project vars if they exist)
@import '@Ui/scss/config/default_variables';

// 3. Project overrides (can override computed defaults)
@import 'project_extend_variables';

// 4. Helpers (mixins, extends, partials)
@import "@Ui/scss/helpers/mixin/_import";
@import "@Ui/scss/helpers/extend/_import";
@import "@Ui/scss/helpers/partial/_import";

// 5. Components
@import '@Ui/scss/component/button';
@import '@Ui/scss/component/thumbnail';
// ...

// 6. Modules
@import '@Ui/scss/module/breadcrumb';
// ...

// 7. Layouts
@import '@Ui/scss/layout/grid';
@import '@Ui/scss/layout/website_layout';
```

To override styles, create `extend_{name}.scss` in the project (e.g., `extend_button.scss`).

See [references/scss-integration.md](references/scss-integration.md) for complete file list and theming variables.

## JS Integration

JS modules export init functions. Import and call them:

```js
import initHeader from '@Ui/js/module/header';
import initRoller from '@Ui/js/module/roller';

initHeader();
initRoller();
```

**JS is NOT auto-loaded by Twig includes.** Including a template does NOT load its JS. The project must separately import and initialize.

Inter-module communication:
```js
import eventEmitter, { EventsTypes } from '@Ui/js/services/events/eventEmitter';
eventEmitter.on(EventsTypes.MENU_OPEN, () => { /* ... */ });
```

See [references/js-integration.md](references/js-integration.md) for full module list and event types.

## Component Finder

| Need | Template | Pattern | JS needed |
|------|----------|---------|-----------|
| Button/CTA | `component/button` | macro: `button` | no |
| Image/thumbnail | `component/thumbnail` | macro: `thumb` | no |
| Tag/badge | `component/label` | macro: `label` | no |
| Heading | `component/title` | include | no |
| Subtitle | `component/subtitle` | include | no |
| Share button | `component/share` | include | `module/share/share` |
| News card | `module/news_cards/news_card_base` | include | no |
| Carousel/slider | `module/roller/roller` | include | `module/roller` |
| Header/nav | `module/header/header_main_v2` | include | `module/header` |
| Footer | `module/footer/footer_main` | include | no |
| Breadcrumb | `module/breadcrumb/breadcrumb` | include | no |
| Pagination | `module/pagination/pagination` | include | no |
| Search form | `module/search/search` | include | `module/search` |
| Link bar | `module/nav/link_bar` | include | no |
| Dropdown | `module/dropdown/dropdown` | include | no |
| Video card | `module/video/video_card` | include | `module/videoCard` |
| Video player | `module/player/player_internal` | include | `module/player` |
| Bottom bar | `module/bottomBar/` (project-defined) | include | `module/bottomBar` |
| Dark mode | n/a (JS only) | n/a | `module/darkMode` |
| Cookie banner | `module/consent/cookie_banner` | include | `consent/cookieBanner` |
| Ad rectangle | `module/ads/rectangle` | include | no |
| Two-col layout | `section/dynamic_content/layout_2_cols_ads` | extends | no |
| Grid layout | `section/dynamic_content/layout_grid_simple` | extends | no |
| Roller layout | `section/dynamic_content/layout_roller` | extends | no |
| Base page | `base.html.twig` | extends | no |
| Grid CSS | n/a (SCSS only) | `@Ui/scss/layout/grid` | no |
| Icons | `<i class="ui-icons">name</i>` | inline HTML | no |

Full catalogs: [component-catalog.md](references/component-catalog.md), [module-catalog.md](references/module-catalog.md), [section-catalog.md](references/section-catalog.md)

## Icons

Use the font icon system:
```html
<i class="ui-icons">icon_name</i>
```

Theme is set via SCSS variable `$website-icon-theme` (`"rounded"` or `"sharp"`).

See [references/icons.md](references/icons.md) for the complete list of 77 icon names.

## Common Gotchas

1. **Macro names differ from filenames**: `thumbnail.html.twig` exports `thumb()`, `button.html.twig` exports `button()`. Always check.

2. **`share` is NOT a macro**: Despite being in `component/`, it uses the include pattern with variables.

3. **`only` is mandatory**: Always append `only` to `{% include %}` calls to prevent scope leakage.

4. **SCSS order breaks silently**: If project theme vars are imported AFTER `default_variables.scss`, overrides are ignored (no error, just wrong values).

5. **`@Ui` maps differently in Twig vs Webpack**: Twig resolves to `templates/`, Webpack resolves to `assets/`. Don't mix them.

6. **JS must be imported separately**: Including a Twig template does NOT auto-load its JS module. Both must be wired up.

7. **`news_card_base` is complex**: 20+ variables. Always read the template source. Minimal usage needs: `type`, `title`, `img_src`, `base_link`, `img_ratio`.

8. **`header_main_v2` remaps variables**: Storybook uses `menu_items` but the template expects `menu_obj`. Check the actual template.

9. **Some templates depend on Symfony functions**: `knp_menu_get()`, `path()`, `asset()`, `format_datetime()` must be available in the consuming project.

10. **Base template requires companion bundles**: `base.html.twig` uses functions from `WebediaSeoBundle` and `WebediaNativePlacementsBundle`. The `UiExtension` provides fallbacks when those are absent.

## References

| File | Contents |
|------|----------|
| [component-catalog.md](references/component-catalog.md) | All 8 components with args, patterns, examples |
| [module-catalog.md](references/module-catalog.md) | All 43 modules grouped by domain |
| [section-catalog.md](references/section-catalog.md) | All 6 section layouts with blocks |
| [scss-integration.md](references/scss-integration.md) | Import order, file list, theming variables |
| [js-integration.md](references/js-integration.md) | Module list, event system, init patterns |
| [icons.md](references/icons.md) | All 77 icon names with usage syntax |

Vendor docs (read when needed for deeper detail):
- `vendor/webedia/ui-bundle/docs/TWIG_TEMPLATES_GUIDE.md`
- `vendor/webedia/ui-bundle/docs/SCSS_GUIDE.md`
- `vendor/webedia/ui-bundle/docs/JS_GUIDE.md`
