
Oro Frontend
- 4 installs
- 2 repo stars
- Updated July 22, 2026
- netresearch/orocommerce-skill
Helps with frontend development tasks.
About
oro-frontend is a Claude Code skill for frontend development. It helps solo builders move faster with AI-assisted coding.
- oro-frontend
- Frontend Development
- AI-coding skill
Oro Frontend by the numbers
- 4 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,817 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/netresearch/orocommerce-skill --skill oro-frontendAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 22, 2026 |
| Repository | netresearch/orocommerce-skill ↗ |
What it does
Helps with frontend development tasks.
Files
OroCommerce v6.1 Frontend Development
Theme Structure
Every OroCommerce theme lives in a bundle's Resources/views/layouts/ directory:
YourBundle/Resources/
├── views/layouts/
│ └── [theme-name]/
│ ├── theme.yml # REQUIRED — defines theme metadata
│ └── config/
│ ├── assets.yml # CSS/JS registration
│ └── jsmodules.yml # JavaScript module paths
└── public/[theme-name]/
├── scss/
│ ├── settings/ # Mixins, functions (compiled FIRST)
│ ├── variables/ # Config variables (compiled SECOND)
│ └── components/ # Component styles (compiled THIRD)
└── js/Theme Registration (theme.yml)
label: My Custom Theme
description: "Optional description"
parent: default
groups: [commerce]
rtl_support: trueTheme name constraint: Must match regex [a-zA-Z][a-zA-Z0-9_-:]*. Use kebab-case. Parent: default for OroCommerce storefront. Child themes inherit SCSS, templates, and JavaScript.
SCSS Organization — 3-Folder Compilation Order
Oro enforces a strict compilation order. Violating it causes build failures: 1. settings/ — Mixins, functions, reusable utilities 2. variables/ — Configuration variables, color palettes 3. components/ — Component styles (BEM: .block__element--modifier)
A mixin defined in components/ is unavailable to variables/. Use !default on variables so child themes can override. Use map.deep-merge() to extend parent palettes without losing keys.
See references/frontend-patterns.md for complete SCSS examples per folder.
Layout Updates
Layout updates are YAML files that modify the layout tree at runtime:
layout:
actions:
- '@add':
id: my_custom_block
parentId: page_main_content
blockType: text
options:
text: 'Custom content here'
- '@setBlockTheme':
themes: 'my_custom_template.html.twig'
- '@move':
id: header_logo
parentId: new_parent_id
sibling: 2
- '@remove':
id: old_widgetSee references/layout-actions.md for the full action reference.
JavaScript Page Components
OroCommerce uses Chaplin.js-based page components initialized from server-rendered HTML via data-page-component-module and data-page-component-options attributes. Register modules in jsmodules.yml under dynamic-imports: for async loading.
See references/frontend-patterns.md for full Chaplin.js examples and jsmodules.yml configuration.
Key Pitfalls
1. SCSS folder order: Defining a variable in components/ won't work if variables/ hasn't compiled yet. Follow the strict order: settings, variables, components.
2. Block naming: Twig layout blocks must end with _widget. ID-specific blocks use underscore prefix: _product_details_widget. Missing either breaks template resolution.
3. Parent theme inheritance: Use map.deep-merge() to extend parent color palettes. Direct assignment replaces the entire palette, losing parent keys.
See Also
references/frontend-patterns.md— SCSS examples, assets.yml, jsmodules.yml, Chaplin.js, template overrides, build commands, storefront vs. back-officereferences/layout-actions.md— Full layout action reference- v6.1 notes | v7.0 notes
Frontend Patterns Reference
SCSS Detailed Examples
Settings (Mixins & Functions)
// scss/settings/primary-settings.scss
@use 'sass:math';
@mixin button-base {
display: inline-block;
padding: math.div(16px, 16px) * 1rem;
border-radius: 4px;
}
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}Variables (Palette & Config)
// scss/variables/primary-variables.scss
@use 'sass:map';
$spacing-unit: 8px;
$border-radius: 4px;
// Deep merge with parent palette
$theme-color-palette: (
'primary': (
'main': #37435c,
'light': #5f6b8f,
'dark': #2a3347,
),
'secondary': (
'c1': #fcb91d,
'c2': #f5a623,
),
) !default;
$color-palette: map.deep-merge($color-palette, $theme-color-palette) !default;Use !default to let child themes override. Use map.deep-merge() to extend parent palettes without losing their keys.
Components (BEM Naming)
// scss/components/button.scss
@use '../settings/primary-settings' as settings;
@use '../variables/primary-variables' as vars;
.button {
@include settings.button-base;
color: map.get(vars.$color-palette, 'primary', 'main');
&__icon {
margin-right: 0.5rem;
}
&__icon--right {
margin-right: 0;
margin-left: 0.5rem;
}
&--primary {
background-color: map.get(vars.$color-palette, 'primary', 'main');
color: white;
}
&--secondary {
background-color: transparent;
border: 1px solid map.get(vars.$color-palette, 'primary', 'main');
}
}Use BEM: .block__element--modifier. This makes component boundaries clear and nesting predictable.
Assets Configuration (assets.yml)
Register CSS and JavaScript files that the build system processes:
# config/assets.yml
css:
inputs:
- 'bundles/acmedemo/my-theme/scss/settings/primary-settings.scss'
- 'bundles/acmedemo/my-theme/scss/variables/primary-variables.scss'
- 'bundles/acmedemo/my-theme/scss/components/button.scss'
- 'bundles/acmedemo/my-theme/scss/components/form.scss'
js:
inputs:
- 'bundles/acmedemo/my-theme/js/app.js'To remove an inherited asset: use ~ (null key):
css:
inputs:
~: 'bundles/parent/parent-theme/scss/old-file.scss'To replace an asset: map the old path to a new one:
css:
inputs:
'bundles/parent/parent-theme/scss/button.scss': 'bundles/acmedemo/my-theme/scss/button.scss'JavaScript Module Configuration (jsmodules.yml)
This file tells the build system which JavaScript modules can be dynamically loaded on pages:
dynamic-imports:
acmedemo:
- acmedemo/js/components/product-reviews
- acmedemo/js/components/image-gallery
- acmedemo/js/views/search-formEach entry should be a valid module path. The build system creates async imports for these, allowing pages to load only the JavaScript they need.
Chaplin.js Page Components
OroCommerce uses Chaplin.js-based page components. A page component is a Backbone.View that initializes with data from the server-rendered HTML.
HTML markup:
<div data-page-component-module="acmedemo/js/components/product-reviews"
data-page-component-options='{"product_id": 42, "sort": "newest"}'>
</div>JavaScript component:
// js/components/product-reviews.js
import Chaplin from 'chaplin';
export default Chaplin.View.extend({
initialize() {
this.options = this.options || {};
this.productId = this.options.product_id;
this.sort = this.options.sort || 'newest';
this.render();
},
render() {
this.$el.html(`<p>Reviews for product ${this.productId}</p>`);
}
});Register the component in jsmodules.yml for dynamic loading.
Twig Block Naming & Resolution
Oro layouts use blocks to render content. Block naming follows a strict resolution order:
1. {% block _<block_id>_widget %} — ID-specific (highest priority) 2. {% block <block_type>_widget %} — Type-specific 3. {% block <parent_block_type>_widget %} — Parent block fallback
All block names end with _widget. ID-specific blocks start with underscore: _product_view_widget.
Example:
{# If block_id is 'product_details' and block_type is 'product_view' #}
{# Highest priority: #}
{% block _product_details_widget %}...{% endblock %}
{# Fall back to type: #}
{% block product_view_widget %}...{% endblock %}
{# Fall back to parent (e.g., container): #}
{% block container_widget %}...{% endblock %}Twig Template Overrides
Override a bundle's template without modifying the original:
templates/bundles/[BundleName]/[OriginalPath]/[Template]Example: To override OroProductBundle/Resources/views/Product/view.html.twig:
templates/bundles/OroProductBundle/Product/view.html.twigSymfony's bundle override mechanism automatically uses this instead of the original. No extra configuration needed.
Storefront vs. Back-Office
Storefront:
- Server-rendered, not a single-page app
- SEO-optimized (traditional form submissions)
- Don't use client-side routing (Backbone.Router)
- Page components are lightweight, augmenting server HTML
Back-Office:
- SPA-like experience with Chaplin routing
- Client-side navigation within the app
- Heavier JavaScript, form handling via AJAX
- Styling uses the same theme system but serves different purposes
Use appropriate patterns for each context. A storefront theme should not implement client-side routing.
Build & Asset Installation
After modifying SCSS, templates, or JavaScript:
# Clear Symfony cache
php bin/console cache:clear
# Install/symlink assets to public/
php bin/console assets:install --symlink
# Build CSS/JS from assets.yml
php bin/console oro:assets:buildThe build command reads assets.yml, compiles SCSS in folder order, and outputs minified CSS and JavaScript to the public directory.
Layout Actions Reference — OroCommerce v6.1
Layout updates use actions to modify the layout tree at runtime. Actions are YAML entries in layout: sections. This reference covers all standard layout actions with examples.
@add
Add a new block to the layout.
- '@add':
id: my_block
parentId: page_main_content
blockType: text
options:
text: 'Block content'
sibling: 0 # Optional: position among siblings (0=first)Parameters:
id(required): Unique block identifierparentId(required): Parent block IDblockType(required): Block type (e.g., 'text', 'container', 'product_list')options(optional): Block-specific options (varies by block type)sibling(optional): Position among siblings (0-based, default=append)
@remove
Remove a block and its children from the layout.
- '@remove':
id: old_widgetParameters:
id(required): Block ID to remove
Removing a parent block removes all children. This is useful for disabling inherited blocks from parent themes.
@move
Relocate a block to a different parent or position.
- '@move':
id: header_logo
parentId: new_parent
sibling: 2Parameters:
id(required): Block ID to moveparentId(optional): New parent block ID (if not specified, parent unchanged)sibling(optional): New position among siblings
The block and its children are moved intact. This is useful for rearranging layout structure without duplicating blocks.
@addTree
Add multiple blocks in a hierarchy in a single action.
- '@addTree':
node:
parentId: page_main_content
blockType: container
options:
attr:
class: 'my-section'
children:
- blockType: text
options:
text: 'Subsection title'
- blockType: container
id: details_container
children:
- blockType: text
options:
text: 'Details content'Parameters:
node(required): Root node definitionparentId(required): Parent block IDblockType(required): Block typeoptions(optional): Block optionschildren(optional): Array of child node definitions (recursive)
Each child node uses the same structure. IDs are auto-generated if not specified.
@setOption
Update an existing block's options.
- '@setOption':
id: my_block
optionName: text
optionValue: 'Updated content'Parameters:
id(required): Block IDoptionName(required): Option keyoptionValue(required): New value
@appendOption
Append a value to an existing option (useful for arrays/lists).
- '@appendOption':
id: product_attributes
optionName: attributes
optionValue:
name: size
label: 'Product Size'Parameters:
id(required): Block IDoptionName(required): Option key (should be an array)optionValue(required): Value to append
@setBlockTheme
Set the Twig template file(s) for rendering blocks.
- '@setBlockTheme':
themes: 'my_custom_template.html.twig'
blocks: [ block_one, block_two ] # Optional: specific blocks onlyParameters:
themes(required): Template file name or pathblocks(optional): Array of specific block type names. If omitted, applies to all blocks.
The template file is resolved relative to the current bundle's Resources/views/layouts/[theme]/ directory.
@configure
Set multiple options on a block at once.
- '@configure':
id: my_block
options:
text: 'New text'
attr:
class: 'highlight'
data-id: '123'Parameters:
id(required): Block IDoptions(required): Object/hash of options to set
This is a convenience action for setting many options without repeated @setOption calls.
Example: Complete Layout Update
layout:
actions:
# Add a container to hold custom content
- '@add':
id: custom_section
parentId: page_main_content
blockType: container
options:
attr:
class: 'custom-section'
# Set the theme for this container
- '@setBlockTheme':
themes: 'my_templates.html.twig'
blocks: [ container ]
# Add content inside
- '@add':
id: section_title
parentId: custom_section
blockType: text
options:
text: 'Special Offers'
- '@add':
id: offers_list
parentId: custom_section
blockType: product_list
options:
product_ids: [ 1, 2, 3 ]
# Remove an inherited block
- '@remove':
id: sidebar_ads
# Move a block to a new location
- '@move':
id: footer_links
parentId: custom_section
sibling: 1
# Update an option on an existing block
- '@setOption':
id: page_title
optionName: title
optionValue: 'Our Products'Block Types (Common)
Not exhaustive; custom block types are defined by bundles.
container— Generic container (no rendering, wraps children)text— Static text contentproduct_view— Product detail pageproduct_list— List of productsform— Symfony form renderingbreadcrumbs— Navigation breadcrumb trailwidget— Generic widget block
Conditions (v6.1)
Some layout systems support conditional actions. While not shown above, Oro's layout engine may support conditions for advanced use cases. Refer to the bundle-specific documentation for conditional block rendering.
Order Matters
Actions execute in the order specified. Depending on a block that hasn't been added yet will fail. Generally, follow this pattern:
1. @add all blocks 2. @setBlockTheme to define rendering 3. @setOption / @appendOption to customize 4. @remove to delete inherited blocks (place early if dependencies exist) 5. @move to rearrange (place last to avoid dependency issues)
Debugging Layout Updates
To see the final layout tree after all actions:
php bin/console oro:debug:layoutThis helps identify which blocks exist, their parents, and their options.
Frontend — v6.1 Notes
Symfony & Toolchain Versions
OroCommerce v6.1 runs on Symfony 5.4 LTS with:
- Twig 3.x — Template syntax and block resolution
- Webpack 5 — Asset bundling (configured via
assets.yml) - Sass 3.x — Modern module system (
@use,@forward); legacy@importis deprecated
Sass Module System
v6.1 uses modern Sass modules. Prefer @use/@forward over @import:
@use 'sass:map';
@use './variables' as vars;
.block {
color: map.get(vars.$color-palette, 'primary', 'main');
}@import is deprecated but still functional in some cases.
Known Issues
Cache Invalidation
After modifying theme.yml or assets.yml, always run both commands:
php bin/console cache:clear
php bin/console oro:assets:buildFailing to clear cache is the most common frontend gotcha.
Block Theme Not Applying
If a custom Twig template is not used, verify: 1. @setBlockTheme action is present in layout YAML 2. Template file path is correct (relative to Resources/views/layouts/[theme]/) 3. Block type name matches the layout definition 4. Cache is cleared
Symlinks on Windows
assets:install --symlink may require admin privileges on Windows. Use assets:install without --symlink (copies instead of symlinking; rebuilds are slower).
Debugging Tools
- Layout inspector:
php bin/console oro:debug:layout— shows block hierarchy - SCSS source maps: Set
assets: { css_source_maps: true }inconfig_dev.yml - Twig debug: Set
twig: { debug: true, strict_variables: true }inconfig_dev.yml - Verbose builds:
php bin/console oro:assets:build --verbose
Performance Notes
- CSS/JS minified automatically in production; unminified in dev
- SCSS compilation is cached and keyed on file hashes; first build is slow
- Lazy-loading JS modules via
jsmodules.ymlreduces initial page load
Frontend — v7.0 Notes
v7.0 is not yet released. This file will be updated when v7.0 stabilizes.
Expected Changes
- TBD