---
name: chromedevtools/ui-eng-vision-local-lit-renderer
source: https://app.decimal.ai/s/chromedevtools-ui-eng-vision-local-lit-renderer@1/SKILL.md
source_sha256: ae75e3daf952
---

# Subskill: Local Lit-HTML Renderer (Pass 2)

This subskill converts consolidated imperative DOM construction helper methods
into reactive, declarative Lit-html templates, rendering them locally inside the
existing element containers.

--------------------------------------------------------------------------------

## 1. Declarative Technology Migration

1.  **Conserve Abstraction Topology**:

    *   Maintain the existing class hierarchy, helper class boundaries, and
        logical groups.
    *   Do not aggressively "flatten" classes or collapse helper abstractions
        into the main view just to coerce a single master template. Pass 2
        should only change the *implementation details* of rendering (imperative
        -> declarative) within existing compartments, not the public API or
        responsibilities of objects.

2.  **Determine Render Lifecycle per Layer**:

    *   **For UI.Widget classes**: Define or update `performUpdate()` to execute
        the main lit `render` call, and use `this.requestUpdate()` to queue
        updates.
    *   **For Delegate/Helper classes**: Identify the custom update hook (e.g.,
        `update()` or `scheduleUpdate()`) and invoke `render()` directly inside
        that method. **Do not** introduce Widget lifecycle methods
        (`performUpdate`) on classes that do not inherit them.

3.  **Import Modern Templating**:

    *   Import the `Lit` rendering system inside the view module:

        ```typescript
        import {html, render, nothing} from '../../ui/lit/lit.js';
        ```

4.  **Modern Component Mapping**:
    *   **MANDATORY**: You **MUST** read and load [ui_engineering.md](../../../docs/ui_engineering.md) first to understand specific component mappings (e.g., Toolbar vs `devtools-toolbar`). Do not assume standard Lit defaults.
    *   If unsure, also consult the [automatic migration code](../../../scripts/eslint_rules/lib/no-imperative-dom-api.ts)
    *   **Prefer Component Built-Ins Over Legacy Boilerplate**: Before porting
        legacy event handlers, comparators, or state variables, check if the
        modern component handles them natively. Drop host-level workarounds in
        favor of declarative component attributes.


5.  **Local Modular Renders**:

    *   If the class contains multiple separate legacy container fields (e.g.,
        fields generated by `appendField` or `createChild` on a parent layout),
        prefer **local modular renders** (rendering templates individually into
        each container) to preserve the legacy layout framework. Do not force a
        monolithic template if doing so violates the existing topology.

6.  **Resolve TypeScript Type Friction**:

    *   Legacy DevTools elements may be typed as `Element`. Lit's `render()`
        function expects `HTMLElement | DocumentFragment`.
    *   When rendering into legacy containers, cast the container using `as
        HTMLElement` or update its class property type definition from `Element`
        to `HTMLElement` to satisfy the TypeScript compiler.
    *   Example: `render(this.template(), this.containerField as HTMLElement);`

7.  **Delegate to Unmigrated Rendering Engines**:

    *   Do not attempt to rewrite complex historical subsystems (like Linkifiers
        or specialized UI utilities) to be "pure Lit" during this pass.
    *   Capitalize on Lit's ability to interpolate standard `HTMLElement` or `Element` instances directly. Treat unmigrated utilities as "black boxes" that generate DOM, and embed their output in standard template expressions: `html`<div>${this.legacyElement}</div>``.
    *   **CRITICAL:** Before treating any component as "unmigrated," you MUST follow steps in Section 4. You are only allowed to use this escape hatch if no declarative migration instructions exist.

8.  **Handle Asynchronous DOM Updates**:

    *   For asynchronous callback-driven updates (e.g., elements updated in a
        `.then()` callback), render the parent container or a placeholder
        template first. Once the data is retrieved, execute a local `render()`
        inside the callback targeting the specific sub-container.

9.  **Template Factorization Strategies**:

    *   **Prefer `nothing`**: Use Lit's `nothing` sentinel instead of empty
        strings `''` or empty templates for conditional rendering.
    *   **Parameterized Fragment Factories**: For repeated UI patterns or
        intermediate layout branches, extract them into parameterized helper
        functions inside the class scope returning `LitTemplate`. This avoids
        monoliths, preserves readability, and reuses template cache strategies.

10. **Visual Parity, CSS Adaptation, and Accessibility**:

    *   **Zero-Tolerance Regression**: Screenshot tests are the ground truth for this phase. Any visual diff (above 0%) in the generated screenshots is unacceptable and must be resolved before proceeding.
    *   **CSS Selector Migration**: When replacing legacy imperative components/widgets with modern web components (e.g., replacing legacy `DataGrid` with `<devtools-data-grid>`), inspect and update the associated `.css` file. Replace legacy class selectors (`.data-grid`) with tag selectors (`devtools-data-grid`).
    *   **Strict Tag/Class Parity**: Do not change tag types (e.g., `span` to
        `div`) or drop class names during template translation, as CSS may
        depend on them.
    *   **Explicit Component Variants**: Modern Custom Element (e.g.
        `<devtools-button>`) defaults may not match legacy appearance.
        Explicitly bind `.data=${{variant: Buttons.Button.Variant.OUTLINED}}`
        (or appropriate variant) rather than relying on defaults.
    *   **Accessibility Preservation**: Convert custom accessibility
        instrumentation (like `ARIAUtils.markAsAlert()`) to native ARIA
        attributes in the template (e.g., `role="alert"`, `aria-live="polite"`).

11. **Render Templates Syntax & Code Movement**:

    *   Surround the expressions containing lit template literals with `//
        clang-format off` and `// clang-format on` to prevent clang-format from
        corrupting template indentation.
    *   **Minimize Code Movement**: Avoid moving existing code to a different location in the file. Put the function signature around the existing code to minimize the diff.
    *   The Gerrit Code Review UI cannot identify moved blocks of unchanged code.
    *   If blocks of code need to be reordered, create a "prefactoring" change that first extracts the code that needs to be reordered into a named helper functions and pause the migration, waiting user confirmation.

12. **Micro-Commit Strategy**:

    *   Do not attempt to convert every helper method and UI component in a single monolithic commit. Break the template extraction into **small, self-contained micro-commits** (e.g., migrating one helper method, toolbar button, or list item render at a time).
    *   Verify with build and run tests after each micro-commit to guarantee zero regressions and 100% visual parity before moving to the next compartment.
    *   Provide the exact list of files and commit message when presenting progress so the change history remains atomic and easy to review.

13. **Wait for confirmation**:

    *   Wait for an explicit confirmation from the user (or Parent Orchestrator Agent) before proceeding to the next step.

--------------------------------------------------------------------------------

## 🔍 Mental Audit (Internal Self-Correction)

*Before reporting back or committing, re-read the instructions and verify:*
1.  ❓ **Tag Parity**: Did I accidentally change any `span` to `div` (or vice versa)?
2.  ❓ **Attribute Drop**: Did I drop any `aria-*`, `role`, or custom data attributes?
3.  ❓ **Clang-Off Boundary**: Is the template wrapped in `// clang-format off`?
4.  ❓ **Build**: Does the code compile and do visual tests pass with 0% diff?