review-component-pr
GitHub用于组件 Pull Request 的代码审查清单,涵盖结构、公共 API、无障碍性、行为、样式及测试等维度,确保代码质量与项目规范。
Trigger Scenarios
Install
npx skills add IgniteUI/igniteui-webcomponents --skill review-component-pr -g -y
SKILL.md
Frontmatter
{
"name": "review-component-pr",
"description": "Comprehensive code review checklist for component pull requests ensuring quality, accessibility, and adherence to project conventions"
}
Review Component PR
A review checklist for pull requests that add or modify components. The rules behind it live in the Coding Guidelines; this skill is the pass over a diff.
When to Use
- Reviewing a PR that adds or changes a component
- Pre-merge quality gate, or a self-review before opening a PR
Review Order
- Structure — are all the required files there?
- Public API — properties, events, docs; this is the part that cannot be changed later
- Accessibility — mandatory, never skipped
- Behavior — lifecycle, state, forms
- Styles and themes
- Tests and generated artifacts
- Build and hygiene
1. Structure
- Component at
src/components/[name]/[name].tswith a single default export - Spec at
src/components/[name]/[name].spec.ts - Story at
stories/[name].stories.ts— filename matches the tag name - Theme scaffold complete:
[name].base.scss,shared/,light/,dark/,themes.ts - Exported from
src/index.tsin alphabetical order - Cross-cutting imports use
#internals/*,#theming/*,#animations/*; component-to-component imports stay relative; every specifier ends in.js - Nothing new under
src/internalsis exported from the public entry point
2. Public API and Documentation
-
tagName,stylesandregister()static members present;register()also registers every dependency rendered in the template -
HTMLElementTagNameMapdeclaration added - Only primitives are attributes; complex types use
attribute: falseand are never reflected - Booleans default to
false - Attribute names are kebab-case, spelled out for multi-word properties
- Events go through
EventEmitterMixinwith a typed event map; names areigc-prefixed camelCase, cancelable ones use the-ingsuffix and their return value is checked - Events are emitted from user interaction, not from property assignment or method calls
- JSDoc carries
@element,@slot,@csspart,@cssproperty,@attr,@default,@eventas applicable, with tags after the description - Deprecations follow
@deprecated since [SemVer]. Use the \[new API]` [type] instead.` - No
igc-tag names in description prose — they ship verbatim intocustom-elements.jsonand every framework wrapper's docs. Allowed only in@element, fenced@exampleblocks, literaligc--containing event/attribute names, and@internal/@hiddenmembers. - Descriptions don't restate the tag ("The label attribute of…"), don't use
Gets/Sets, and booleans start with "Whether" describing thetruestate accurately
# Quick leak check — should return nothing outside @element/@example
grep -rn "igc-" --include="*.ts" src/ \
| grep -E "^\S+:[0-9]+:\s*\*" \
| grep -vE "@element|@example|\.spec\.ts"
3. Accessibility
- The spec contains the mandatory a11y audit (
shadowDomand light DOM) - Semantic elements used instead of
divs with click handlers - ARIA set through
addInternalsController(initialARIA,setARIA()) — neverthis.role = '…';reflectRole: truewhen attribute-only tooling must see the role - Keyboard interaction implemented through
addKeybindings(Tab, arrows, Enter/Space, Escape, Home/End as applicable) with visible focus indicators - Composite hosts wrapping an input-shaped component project their semantics with
addAriaProjector/addAriaTargetinstead of settingrole/aria-*on the host or the wrapper - Cross-root relations use ARIA element reflection, never IDREFs
- Theme selectors for composite anchors key off the mirrored
data-role/data-haspopupattributes, notrole/aria-* - No
publicmembers tagged@hidden/@internaladded for cross-component access — useinternalsOf() - Cross-root ARIA is covered by
runExternalLabelAssociationTests/runAriaProjectionTests; reflected relations are asserted by identity readback, withaxeReflectedRelationsOptionssuppressing the knownaria-required-attrfalse positive
4. Behavior
- Region fences and member order follow the standard component structure
- Internal API is
_-prefixed; no native private fields (#);readonlyon controllers and other non-reassigned fields - No
any; explicit return types except where obviously noise - Derived state computed in
willUpdate(), side effects inupdate()withsuper.update()called; guarded bychangedProperties.has() - No new
@watchusages - Existing controllers reused rather than reimplemented (slots, observers, root click, keybindings, gestures, i18n)
- Dynamically added listeners on
window/documentare removed indisconnectedCallback; listeners in templates and on the host are not manually cleaned up - User-facing strings come from the i18n controller, not inlined in templates
- Form controls: extend the right form-associated mixin, own their
_formValuethroughcreateFormValueState, expose validators via__validators(reusing#internals/validators.js), update throughsetValueAndFormState, call_validate()from constraint-affecting setters, and wire_handleBlur/_handleEnterKeydownon the native editor - Form controls don't reimplement touched/pristine/invalid bookkeeping; overrides of
formResetCallbackcallsuper
5. Styles and Themes
- Only
.scssedited — no generated.css.tsin the diff - Load-path specifiers (
@use 'styles/utilities' as *), no relative global imports - Values read through
var-get()and the theming functions; nothing hardcoded - Part selectors use
[part~='…'] - All four themes covered in light and dark; dark files emit only the
diff() -
themes.tsaggregates every theme file that was added -
:hosthas an appropriatedisplay; selector specificity kept low
6. Tests and Generated Artifacts
-
defineComponents()in thebefore()hook;elementUpdated()after programmatic changes - Coverage for defaults, property/attribute reflection, events, interaction and edge cases
- Interaction driven by the shared simulators from
#internals/testing/simulate.spec.js, not rawclick()/ hand-built events - Form controls tested through
createFormAssociatedTestBedand the validity helpers - The story's
// region default … // endregionblock was regenerated (npm run cem && npm run build:meta), not hand-edited, and is committed - Hand-written stories cover the states a user cares about
- CHANGELOG updated
7. Build and Hygiene
-
npm run check(aliases, dependency rules, types) passes -
npm run lintpasses — oxlint, lit-analyzer, oxfmt, stylelint -
npm run testpasses - No leftover
console.log/debugger, no commented-out code, no unexplained magic numbers - No new heavy third-party dependency
Frequent Findings
| Finding | Why it matters |
|---|---|
Missing addThemingController |
The component never reacts to theme changes |
Relative import into internals/theming |
npm run check fails; alias is the contract |
Alias added to package.json only |
Breaks only for consumers of the published package |
igc- tag name in a description |
Ships verbatim into every framework wrapper's API docs |
| Hand-edited story metadata | Reverts on the next npm run build:meta |
.css.ts file in the diff |
Generated and gitignored — the .scss is the source |
[part='base'] with partMap |
Selector silently stops matching once a second part name is emitted |
ARIA on a delegatesFocus host |
Assistive technology reads the native editor, not the host |
New @hidden public member |
Leaks into the compiled public API — use internalsOf() |
Boolean property defaulting to true |
Cannot be turned off from markup |
@watch in new code |
Lifecycle hooks are the supported path |
Verdict
Request changes when: the a11y audit is missing or failing, ARIA is set on the wrong
element, any types or native private fields appear, generated artifacts are hand-edited or
missing, themes are incomplete, or the public API is undocumented.
Approve when the checklist passes, npm run check, npm run lint and npm run test are
green, and the public API reads the way it will be documented for users.
Be specific in feedback: name the file, the line and the guideline it maps to.
Version History
- 7.2.4 Current 2026-08-20 11:42


