-
Notifications
You must be signed in to change notification settings - Fork 54
Add optional element name parameter to @controller decorator #330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
c09e428 to
fff47a5
Compare
Co-authored-by: dgreif <3026298+dgreif@users.noreply.github.com>
Co-authored-by: dgreif <3026298+dgreif@users.noreply.github.com>
Co-authored-by: dgreif <3026298+dgreif@users.noreply.github.com>
8d5ce1d to
811be96
Compare
|
I noticed the tests flake quite a bit on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for specifying custom element names in the @controller decorator to handle production builds where class names are minified. The decorator now accepts an optional string parameter for explicit element naming while maintaining backward compatibility with automatic name derivation from class names.
Changes:
- Enhanced
@controllerdecorator with function overloads to accept optional custom element name parameter - Updated core implementation to thread custom name through registration process
- Added comprehensive test coverage for decorator and function syntax with custom names
- Documented the new feature with examples and use cases
- Updated Node.js version from 16 to 24 across CI/CD workflows and development containers
- Increased test timeout to 30 seconds
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/controller.ts |
Added function overloads to support optional custom element name parameter |
src/core.ts |
Updated CatalystDelegate constructor to accept and pass through optional element name |
src/register.ts |
Modified to use provided custom name instead of deriving from class name when available |
test/controller.ts |
Added tests for custom name registration with both decorator and function syntax |
docs/_guide/your-first-component.md |
Documented custom element name syntax and minification use case |
web-test-runner.config.js |
Increased test finish timeout to 30 seconds |
.github/workflows/publish.yml |
Updated Node.js version from 16.x to 24.x |
.github/workflows/nodejs.yml |
Updated Node.js version from 16.x to 24.x |
.github/workflows/lighthouse.yml |
Updated Node.js version from 16.x to 24.x |
.devcontainer/devcontainer.json |
Updated Node.js variant from 16 to 24 |
.devcontainer/Dockerfile |
Updated Node.js variant from 16 to 24 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| it('registers element with custom name when provided', async () => { | ||
| @controller('happy-widget') | ||
| class SomeClass extends HTMLElement {} | ||
| instance = await fixture(html`<happy-widget />`) | ||
| expect(instance).to.be.instanceof(SomeClass) | ||
| }) | ||
|
|
||
| it('registers element with custom name using function syntax', async () => { | ||
| controller('custom-element-name')(class AnotherClass extends HTMLElement {}) | ||
| instance = await fixture(html`<custom-element-name />`) | ||
| expect(instance).to.exist | ||
| }) | ||
|
|
||
| it('adds data-catalyst to elements with custom names', async () => { | ||
| @controller('custom-named-element') | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| class CustomNamedElement extends HTMLElement {} | ||
|
|
||
| instance = await fixture(html`<custom-named-element />`) | ||
| expect(instance.hasAttribute('data-catalyst')).to.equal(true) | ||
| expect(instance.getAttribute('data-catalyst')).to.equal('') | ||
| }) |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test coverage is missing for edge cases when using custom element names. Consider adding tests for invalid custom element names (e.g., names without hyphens, reserved names, uppercase characters) to verify that appropriate errors are thrown or handled correctly.
| export function register(classObject: CustomElementClass, name?: string): CustomElementClass { | ||
| const tagName = name || dasherize(classObject.name).replace(/-element$/, '') |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom element name parameter is not validated. According to the HTML specification, custom element names must contain a hyphen to avoid conflicts with standard HTML elements. Consider adding validation to ensure the provided name contains a hyphen and follows custom element naming rules, or rely on the browser's customElements.define to throw appropriate errors for invalid names.
The
@controllerdecorator derives element names from class names via kebab-case conversion, which breaks when class names are minified in production builds.Changes
src/controller.ts: Add function overload accepting optional string parameter for explicit element namesrc/core.ts: Thread optionalelementNameparameter throughCatalystDelegateconstructorsrc/register.ts: Use provided name instead of deriving from class name when presenttest/controller.ts: Add tests for decorator and function syntax with custom namesdocs/_guide/your-first-component.md: Document custom name syntax and minification use caseUsage
Backward compatible—omitting the parameter preserves existing automatic naming behavior.
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
accounts.google.com/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3528 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-Ygvhnb --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12664389469337770198,2372341684580270968,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)/opt/google/chrome/chrome /usr/bin/google-chrome-stable --disable-REDACTED-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=Translate,BackForwardCache --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-sync --force-color-profile=srgb --metrics-recording-only(dns block)/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3848 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-ZW8rdt --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,13741986308328416240,10430580951888999949,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)clients2.google.com/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3528 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-Ygvhnb --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12664389469337770198,2372341684580270968,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)/opt/google/chrome/chrome /usr/bin/google-chrome-stable --disable-REDACTED-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=Translate,BackForwardCache --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-sync --force-color-profile=srgb --metrics-recording-only(dns block)/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3848 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-ZW8rdt --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,13741986308328416240,10430580951888999949,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)safebrowsingohttpgateway.googleapis.com/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3528 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-Ygvhnb --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12664389469337770198,2372341684580270968,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)/opt/google/chrome/chrome /usr/bin/google-chrome-stable --disable-REDACTED-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=Translate,BackForwardCache --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-sync --force-color-profile=srgb --metrics-recording-only(dns block)/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3848 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-ZW8rdt --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,13741986308328416240,10430580951888999949,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)www.google.com/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3528 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-Ygvhnb --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12664389469337770198,2372341684580270968,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)/opt/google/chrome/chrome /usr/bin/google-chrome-stable --disable-REDACTED-networking --enable-features=NetworkService,NetworkServiceInProcess --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=Translate,BackForwardCache --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-sync --force-color-profile=srgb --metrics-recording-only(dns block)/proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=3848 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-ZW8rdt --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,13741986308328416240,10430580951888999949,262144 --enable-features=NetworkService,NetworkServiceInProcess --disable-features=BackForwardCache,PaintHolding,Translate --variations-seed-version --trace-process-track-uuid=3190708989122997041(dns block)If you need me to access, download, or install something from one of these locations, you can either:
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.