or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-web-features.mdbrowser-page-control.mdcore-debugging.mddevice-testing.mddom-styling.mdindex.mdnetwork-performance.mdstorage-data.md
tile.json

dom-styling.mddocs/

DOM and Styling

DOM tree manipulation, CSS inspection and modification, and styling analysis. This covers domains that provide access to the document structure, CSS rules, and visual styling information.

Capabilities

DOM Domain

DOM tree manipulation and inspection for accessing and modifying document structure.

namespace Protocol.DOM {
  type NodeId = integer;
  type BackendNodeId = integer;
  type PseudoType = ('first-line' | 'first-letter' | 'before' | 'after' | 'marker' | 'backdrop' | 'selection' | 'target-text' | 'spelling-error' | 'grammar-error' | 'highlight' | 'first-line-inherited' | 'scrollbar' | 'scrollbar-thumb' | 'scrollbar-button' | 'scrollbar-track' | 'scrollbar-track-piece' | 'scrollbar-corner' | 'resizer' | 'input-list-button' | 'view-transition' | 'view-transition-group' | 'view-transition-image-pair' | 'view-transition-old' | 'view-transition-new');
  type ShadowRootType = ('user-agent' | 'open' | 'closed');
  type CompatibilityMode = ('QuirksMode' | 'LimitedQuirksMode' | 'NoQuirksMode');

  interface Node {
    nodeId: NodeId;
    parentId?: NodeId;
    backendNodeId: BackendNodeId;
    nodeType: integer;
    nodeName: string;
    localName: string;
    nodeValue: string;
    childNodeCount?: integer;
    children?: Node[];
    attributes?: string[];
    documentURL?: string;
    baseURL?: string;
    publicId?: string;
    systemId?: string;
    xmlVersion?: string;
    name?: string;
    value?: string;
    pseudoType?: PseudoType;
    pseudoIdentifier?: string;
    shadowRootType?: ShadowRootType;
    frameId?: Page.FrameId;
    contentDocument?: Node;
    shadowRoots?: Node[];
    templateContent?: Node;
    pseudoElements?: Node[];
    importedDocument?: Node;
    distributedNodes?: BackendNode[];
    isSVG?: boolean;
    compatibilityMode?: CompatibilityMode;
    assignedSlot?: BackendNode;
  }

  interface BackendNode {
    nodeType: integer;
    nodeName: string;
    backendNodeId: BackendNodeId;
  }

  interface GetDocumentRequest {
    depth?: integer;
    pierce?: boolean;
  }

  interface GetDocumentResponse {
    root: Node;
  }

  interface QuerySelectorRequest {
    nodeId: NodeId;
    selector: string;
  }

  interface QuerySelectorResponse {
    nodeId: NodeId;
  }

  interface QuerySelectorAllRequest {
    nodeId: NodeId;
    selector: string;
  }

  interface QuerySelectorAllResponse {
    nodeIds: NodeId[];
  }

  interface GetAttributesRequest {
    nodeId: NodeId;
  }

  interface GetAttributesResponse {
    attributes: string[];
  }

  interface SetAttributeValueRequest {
    nodeId: NodeId;
    name: string;
    value: string;
  }

  interface RemoveAttributeRequest {
    nodeId: NodeId;
    name: string;
  }

  interface GetOuterHTMLRequest {
    nodeId?: NodeId;
    backendNodeId?: BackendNodeId;
    objectId?: Runtime.RemoteObjectId;
  }

  interface GetOuterHTMLResponse {
    outerHTML: string;
  }

  interface SetOuterHTMLRequest {
    nodeId: NodeId;
    outerHTML: string;
  }

  interface DocumentUpdatedEvent {}

  interface SetChildNodesEvent {
    parentId: NodeId;
    nodes: Node[];
  }

  interface AttributeModifiedEvent {
    nodeId: NodeId;
    name: string;
    value: string;
  }

  interface AttributeRemovedEvent {
    nodeId: NodeId;
    name: string;
  }

  interface CharacterDataModifiedEvent {
    nodeId: NodeId;
    characterData: string;
  }

  interface ChildNodeInsertedEvent {
    parentNodeId: NodeId;
    previousNodeId: NodeId;
    node: Node;
  }

  interface ChildNodeRemovedEvent {
    parentNodeId: NodeId;
    nodeId: NodeId;
  }
}

Usage Example:

import Protocol from "devtools-protocol/types/protocol";

// Get the document root
async function getDocument(): Promise<Protocol.DOM.Node> {
  const request: Protocol.DOM.GetDocumentRequest = {
    depth: -1,
    pierce: true
  };
  
  // Implementation would send DOM.getDocument
  const response: Protocol.DOM.GetDocumentResponse = {
    root: {
      nodeId: 1,
      backendNodeId: 1,
      nodeType: 9, // Document node
      nodeName: "#document",
      localName: "",
      nodeValue: "",
      childNodeCount: 1,
      documentURL: "https://example.com",
      children: []
    }
  };
  
  return response.root;
}

// Query for elements
async function findElementsBySelector(nodeId: Protocol.DOM.NodeId, selector: string): Promise<Protocol.DOM.NodeId[]> {
  const request: Protocol.DOM.QuerySelectorAllRequest = {
    nodeId,
    selector
  };
  
  // Implementation would send DOM.querySelectorAll
  const response: Protocol.DOM.QuerySelectorAllResponse = {
    nodeIds: [2, 3, 4]
  };
  
  return response.nodeIds;
}

// Modify element attributes
async function setElementAttribute(nodeId: Protocol.DOM.NodeId, name: string, value: string): Promise<void> {
  const request: Protocol.DOM.SetAttributeValueRequest = {
    nodeId,
    name,
    value
  };
  
  // Implementation would send DOM.setAttributeValue
}

// Handle DOM change events
function onAttributeModified(event: Protocol.DOM.AttributeModifiedEvent) {
  console.log(`Attribute ${event.name} changed to "${event.value}" on node ${event.nodeId}`);
}

function onChildNodeInserted(event: Protocol.DOM.ChildNodeInsertedEvent) {
  console.log(`Child node inserted into ${event.parentNodeId}:`, event.node.nodeName);
}

CSS Domain

CSS style inspection and modification for analyzing and changing element styling.

namespace Protocol.CSS {
  type StyleSheetId = string;
  type CSSRuleId = string;

  interface CSSRule {
    styleSheetId?: StyleSheetId;
    selectorList: SelectorList;
    origin: StyleSheetOrigin;
    style: CSSStyle;
    media?: CSSMedia[];
    containerQueries?: CSSContainerQuery[];
    supports?: CSSSupports[];
    layers?: CSSLayer[];
    scopes?: CSSScope[];
  }

  interface CSSStyle {
    styleSheetId?: StyleSheetId;
    cssProperties: CSSProperty[];
    shorthandEntries: ShorthandEntry[];
    cssText?: string;
    range?: SourceRange;
  }

  interface CSSProperty {
    name: string;
    value: string;
    important?: boolean;
    implicit?: boolean;
    text?: string;
    parsedOk?: boolean;
    disabled?: boolean;
    range?: SourceRange;
    longhandProperties?: CSSProperty[];
  }

  interface SelectorList {
    selectors: CSSSelector[];
    text: string;
  }

  interface CSSSelector {
    text: string;
    range?: SourceRange;
  }

  interface CSSStyleSheetHeader {
    styleSheetId: StyleSheetId;
    frameId: Page.FrameId;
    sourceURL: string;
    sourceMapURL?: string;
    origin: StyleSheetOrigin;
    title: string;
    ownerNode?: DOM.BackendNodeId;
    disabled: boolean;
    hasSourceURL?: boolean;
    isInline: boolean;
    isMutable: boolean;
    isConstructed: boolean;
    startLine: number;
    startColumn: number;
    length: number;
    endLine: number;
    endColumn: number;
  }

  interface GetComputedStyleForNodeRequest {
    nodeId: DOM.NodeId;
  }

  interface GetComputedStyleForNodeResponse {
    computedStyle: CSSComputedStyleProperty[];
  }

  interface CSSComputedStyleProperty {
    name: string;
    value: string;
  }

  interface GetInlineStylesForNodeRequest {
    nodeId: DOM.NodeId;
  }

  interface GetInlineStylesForNodeResponse {
    inlineStyle?: CSSStyle;
    attributesStyle?: CSSStyle;
  }

  interface GetMatchedStylesForNodeRequest {
    nodeId: DOM.NodeId;
  }

  interface GetMatchedStylesForNodeResponse {
    inlineStyle?: CSSStyle;
    attributesStyle?: CSSStyle;
    matchedCSSRules?: RuleMatch[];
    pseudoElements?: PseudoElementMatches[];
    inherited?: InheritedStyleEntry[];
    inheritedPseudoElements?: InheritedPseudoElementMatches[];
    cssKeyframesRules?: CSSKeyframesRule[];
    cssPositionTryRules?: CSSPositionTryRule[];
  }

  interface RuleMatch {
    rule: CSSRule;
    matchingSelectors: integer[];
  }

  interface SetStyleTextsRequest {
    edits: StyleDeclarationEdit[];
  }

  interface SetStyleTextsResponse {
    styles: CSSStyle[];
  }

  interface StyleDeclarationEdit {
    styleSheetId: StyleSheetId;
    range: SourceRange;
    text: string;
  }

  interface GetStyleSheetTextRequest {
    styleSheetId: StyleSheetId;
  }

  interface GetStyleSheetTextResponse {
    text: string;
  }

  interface SetStyleSheetTextRequest {
    styleSheetId: StyleSheetId;
    text: string;
  }

  interface StyleSheetAddedEvent {
    header: CSSStyleSheetHeader;
  }

  interface StyleSheetRemovedEvent {
    styleSheetId: StyleSheetId;
  }

  interface StyleSheetChangedEvent {
    styleSheetId: StyleSheetId;
  }
}

Usage Example:

import Protocol from "devtools-protocol/types/protocol";

// Get computed styles for an element
async function getElementStyles(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]> {
  const request: Protocol.CSS.GetComputedStyleForNodeRequest = {
    nodeId
  };
  
  // Implementation would send CSS.getComputedStyleForNode
  const response: Protocol.CSS.GetComputedStyleForNodeResponse = {
    computedStyle: [
      { name: "color", value: "rgb(0, 0, 0)" },
      { name: "font-size", value: "16px" },
      { name: "display", value: "block" }
    ]
  };
  
  return response.computedStyle;
}

// Get matched CSS rules for an element
async function getMatchedRules(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.RuleMatch[]> {
  const request: Protocol.CSS.GetMatchedStylesForNodeRequest = {
    nodeId
  };
  
  // Implementation would send CSS.getMatchedStylesForNode
  const response: Protocol.CSS.GetMatchedStylesForNodeResponse = {
    matchedCSSRules: [
      {
        rule: {
          selectorList: {
            selectors: [{ text: ".example" }],
            text: ".example"
          },
          origin: "regular",
          style: {
            cssProperties: [
              { name: "color", value: "red", important: false }
            ],
            shorthandEntries: [],
            cssText: "color: red;"
          }
        },
        matchingSelectors: [0]
      }
    ]
  };
  
  return response.matchedCSSRules || [];
}

// Modify CSS styles
async function modifyElementStyle(styleSheetId: Protocol.CSS.StyleSheetId, range: Protocol.CSS.SourceRange, newText: string): Promise<Protocol.CSS.CSSStyle[]> {
  const request: Protocol.CSS.SetStyleTextsRequest = {
    edits: [{
      styleSheetId,
      range,
      text: newText
    }]
  };
  
  // Implementation would send CSS.setStyleTexts
  const response: Protocol.CSS.SetStyleTextsResponse = {
    styles: []
  };
  
  return response.styles;
}

// Handle CSS events
function onStyleSheetAdded(event: Protocol.CSS.StyleSheetAddedEvent) {
  console.log(`Stylesheet added: ${event.header.sourceURL}`);
}

function onStyleSheetChanged(event: Protocol.CSS.StyleSheetChangedEvent) {
  console.log(`Stylesheet changed: ${event.styleSheetId}`);
}

DOMDebugger Domain

DOM-related debugging features for setting breakpoints on DOM mutations and events.

namespace Protocol.DOMDebugger {
  type DOMBreakpointType = ('subtree-modified' | 'attribute-modified' | 'node-removed');
  type CSPViolationType = ('trustedtype-sink-violation' | 'trustedtype-policy-violation');

  interface EventListener {
    type: string;
    useCapture: boolean;
    passive: boolean;
    once: boolean;
    scriptId: Runtime.ScriptId;
    lineNumber: integer;
    columnNumber: integer;
    handler?: Runtime.RemoteObject;
    originalHandler?: Runtime.RemoteObject;
    backendNodeId?: DOM.BackendNodeId;
  }

  interface SetDOMBreakpointRequest {
    nodeId: DOM.NodeId;
    type: DOMBreakpointType;
  }

  interface RemoveDOMBreakpointRequest {
    nodeId: DOM.NodeId;
    type: DOMBreakpointType;
  }

  interface SetEventListenerBreakpointRequest {
    eventName: string;
    targetName?: string;
  }

  interface RemoveEventListenerBreakpointRequest {
    eventName: string;
    targetName?: string;
  }

  interface GetEventListenersRequest {
    objectId: Runtime.RemoteObjectId;
    depth?: integer;
    pierce?: boolean;
  }

  interface GetEventListenersResponse {
    listeners: EventListener[];
  }
}

DOMSnapshot Domain

DOM tree snapshots for analysis and testing purposes.

namespace Protocol.DOMSnapshot {
  interface DOMNode {
    nodeType: integer;
    nodeName: string;
    nodeValue: string;
    textValue?: string;
    inputValue?: string;
    inputChecked?: boolean;
    optionSelected?: boolean;
    backendNodeId: DOM.BackendNodeId;
    childNodeIndexes?: integer[];
    attributes?: NameValue[];
    pseudoElementIndexes?: integer[];
    layoutNodeIndex?: integer;
    documentURL?: string;
    baseURL?: string;
    contentLanguage?: string;
    documentEncoding?: string;
    publicId?: string;
    systemId?: string;
    frameId?: Page.FrameId;
    contentDocumentIndex?: integer;
    pseudoType?: DOM.PseudoType;
    shadowRootType?: DOM.ShadowRootType;
    isClickable?: boolean;
    eventListeners?: DOMDebugger.EventListener[];
    currentSourceURL?: string;
    originURL?: string;
    scrollOffsetX?: number;
    scrollOffsetY?: number;
  }

  interface LayoutTreeNode {
    domNodeIndex: integer;
    boundingBox: DOM.Rect;
    layoutText?: string;
    inlineTextNodes?: InlineTextBox[];
    styleIndex?: integer;
    paintOrder?: integer;
    isStackingContext?: boolean;
  }

  interface ComputedStyle {
    properties: NameValue[];
  }

  interface NameValue {
    name: string;
    value: string;
  }

  interface CaptureSnapshotRequest {
    computedStyles: string[];
    includePaintOrder?: boolean;
    includeDOMRects?: boolean;
    includeBlendedBackgroundColors?: boolean;
    includeTextColorOpacities?: boolean;
  }

  interface CaptureSnapshotResponse {
    documents: DocumentSnapshot[];
    strings: string[];
  }

  interface DocumentSnapshot {
    documentURL: integer;
    title: integer;
    baseURL: integer;
    contentLanguage: integer;
    encodingName: integer;
    publicId: integer;
    systemId: integer;
    frameId: integer;
    nodes: DOMNode[];
    layout: LayoutTreeSnapshot;
    textBoxes: TextBoxSnapshot;
    scrollOffsetX?: number;
    scrollOffsetY?: number;
    contentWidth?: number;
    contentHeight?: number;
  }
}

Common Usage Patterns

DOM Inspection and Manipulation

import Protocol from "devtools-protocol/types/protocol";

class DOMInspector {
  private document: Protocol.DOM.Node | null = null;

  async initialize(): Promise<void> {
    // Get the document
    const docResponse = await this.getDocument();
    this.document = docResponse.root;
  }

  private async getDocument(): Promise<Protocol.DOM.GetDocumentResponse> {
    const request: Protocol.DOM.GetDocumentRequest = {
      depth: -1,
      pierce: true
    };
    
    // Implementation would send DOM.getDocument
    return {
      root: {
        nodeId: 1,
        backendNodeId: 1,
        nodeType: 9,
        nodeName: "#document",
        localName: "",
        nodeValue: "",
        children: []
      }
    };
  }

  async findElementsByText(text: string): Promise<Protocol.DOM.NodeId[]> {
    if (!this.document) throw new Error("Document not loaded");
    
    const selector = `//*[contains(text(), "${text}")]`;
    
    // Implementation would use XPath or text-based search
    return [];
  }

  async modifyElementText(nodeId: Protocol.DOM.NodeId, newText: string): Promise<void> {
    // Get current HTML
    const htmlRequest: Protocol.DOM.GetOuterHTMLRequest = { nodeId };
    // Implementation would get current HTML and modify it
    
    const setRequest: Protocol.DOM.SetOuterHTMLRequest = {
      nodeId,
      outerHTML: `<div>${newText}</div>`
    };
    
    // Implementation would send DOM.setOuterHTML
  }

  setupDOMChangeListeners(): void {
    this.onAttributeModified = (event: Protocol.DOM.AttributeModifiedEvent) => {
      console.log(`Attribute changed: ${event.name}="${event.value}" on node ${event.nodeId}`);
    };

    this.onChildNodeInserted = (event: Protocol.DOM.ChildNodeInsertedEvent) => {
      console.log(`Node inserted: ${event.node.nodeName} into ${event.parentNodeId}`);
    };

    this.onChildNodeRemoved = (event: Protocol.DOM.ChildNodeRemovedEvent) => {
      console.log(`Node removed: ${event.nodeId} from ${event.parentNodeId}`);
    };
  }
}

CSS Style Analysis

import Protocol from "devtools-protocol/types/protocol";

class StyleAnalyzer {
  async analyzeElementStyles(nodeId: Protocol.DOM.NodeId): Promise<StyleAnalysis> {
    // Get computed styles
    const computedRequest: Protocol.CSS.GetComputedStyleForNodeRequest = { nodeId };
    const computedStyles = await this.getComputedStyles(computedRequest);
    
    // Get matched rules
    const matchedRequest: Protocol.CSS.GetMatchedStylesForNodeRequest = { nodeId };
    const matchedRules = await this.getMatchedRules(matchedRequest);
    
    // Get inline styles
    const inlineRequest: Protocol.CSS.GetInlineStylesForNodeRequest = { nodeId };
    const inlineStyles = await this.getInlineStyles(inlineRequest);
    
    return {
      computed: computedStyles,
      matched: matchedRules,
      inline: inlineStyles
    };
  }

  private async getComputedStyles(request: Protocol.CSS.GetComputedStyleForNodeRequest): Promise<Protocol.CSS.CSSComputedStyleProperty[]> {
    // Implementation would send CSS.getComputedStyleForNode
    return [];
  }

  private async getMatchedRules(request: Protocol.CSS.GetMatchedStylesForNodeRequest): Promise<Protocol.CSS.RuleMatch[]> {
    // Implementation would send CSS.getMatchedStylesForNode
    return [];
  }

  private async getInlineStyles(request: Protocol.CSS.GetInlineStylesForNodeRequest): Promise<{ inlineStyle?: Protocol.CSS.CSSStyle; attributesStyle?: Protocol.CSS.CSSStyle }> {
    // Implementation would send CSS.getInlineStylesForNode
    return {};
  }

  async modifyElementStyle(nodeId: Protocol.DOM.NodeId, property: string, value: string): Promise<void> {
    // First get the current inline styles
    const inlineRequest: Protocol.CSS.GetInlineStylesForNodeRequest = { nodeId };
    const inlineResponse = await this.getInlineStyles(inlineRequest);
    
    if (inlineResponse.inlineStyle) {
      // Modify existing inline style
      const newCssText = `${inlineResponse.inlineStyle.cssText} ${property}: ${value};`;
      
      const editRequest: Protocol.CSS.SetStyleTextsRequest = {
        edits: [{
          styleSheetId: inlineResponse.inlineStyle.styleSheetId!,
          range: inlineResponse.inlineStyle.range!,
          text: newCssText
        }]
      };
      
      // Implementation would send CSS.setStyleTexts
    } else {
      // Add new inline style via DOM attribute
      const setAttrRequest: Protocol.DOM.SetAttributeValueRequest = {
        nodeId,
        name: "style",
        value: `${property}: ${value};`
      };
      
      // Implementation would send DOM.setAttributeValue
    }
  }
}

interface StyleAnalysis {
  computed: Protocol.CSS.CSSComputedStyleProperty[];
  matched: Protocol.CSS.RuleMatch[];
  inline: { inlineStyle?: Protocol.CSS.CSSStyle; attributesStyle?: Protocol.CSS.CSSStyle };
}

DOM Debugging

import Protocol from "devtools-protocol/types/protocol";

class DOMDebugger {
  async setBreakpointOnNodeChanges(nodeId: Protocol.DOM.NodeId): Promise<void> {
    // Set breakpoint on subtree modifications
    const subtreeRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
      nodeId,
      type: 'subtree-modified'
    };
    
    // Set breakpoint on attribute modifications
    const attrRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
      nodeId,
      type: 'attribute-modified'
    };
    
    // Set breakpoint on node removal
    const removeRequest: Protocol.DOMDebugger.SetDOMBreakpointRequest = {
      nodeId,
      type: 'node-removed'
    };
    
    // Implementation would send DOMDebugger.setDOMBreakpoint for each
  }

  async setEventListenerBreakpoints(events: string[]): Promise<void> {
    for (const eventName of events) {
      const request: Protocol.DOMDebugger.SetEventListenerBreakpointRequest = {
        eventName
      };
      
      // Implementation would send DOMDebugger.setEventListenerBreakpoint
    }
  }

  async analyzeEventListeners(objectId: Protocol.Runtime.RemoteObjectId): Promise<Protocol.DOMDebugger.EventListener[]> {
    const request: Protocol.DOMDebugger.GetEventListenersRequest = {
      objectId,
      depth: 10,
      pierce: true
    };
    
    // Implementation would send DOMDebugger.getEventListeners
    const response: Protocol.DOMDebugger.GetEventListenersResponse = {
      listeners: []
    };
    
    return response.listeners;
  }
}