CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-material-design-lite

Material Design Components in CSS, JS and HTML providing a comprehensive implementation of Google's Material Design specification for web applications.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

component-management.mddocs/

Component Management

Core system for managing Material Design Lite component lifecycle, registration, and upgrades. The component handler provides centralized control over when and how MDL components are initialized and managed.

Capabilities

Component Handler

The global componentHandler object provides the main API for component lifecycle management.

/**
 * Global component handler for managing MDL components
 * Available as window.componentHandler
 */
interface ComponentHandler {
  /** 
   * Searches existing DOM for elements of specified component type and upgrades them
   * @param optJsClass - Optional programmatic name of the element class to upgrade
   * @param optCssClass - Optional CSS class name of elements to upgrade
   */
  upgradeDom(optJsClass?: string, optCssClass?: string): void;
  
  /**
   * Upgrades a specific element rather than all in the DOM
   * @param element - The element to upgrade
   * @param optJsClass - Optional name of the class to upgrade the element to
   */
  upgradeElement(element: Element, optJsClass?: string): void;
  
  /**
   * Upgrades a specific list of elements rather than all in the DOM
   * @param elements - The elements to upgrade
   */
  upgradeElements(elements: Element[] | NodeList | HTMLCollection): void;
  
  /**
   * Upgrades all registered components found in the current DOM
   * Automatically called on window load
   */
  upgradeAllRegistered(): void;
  
  /**
   * Allows user to be alerted to any upgrades performed for a given component type
   * @param jsClass - The class name of the MDL component to hook into
   * @param callback - Function to call upon upgrade, receives HTMLElement parameter
   */
  registerUpgradedCallback(jsClass: string, callback: (element: HTMLElement) => void): void;
  
  /**
   * Registers a class for future use and attempts to upgrade existing DOM
   * @param config - The registration configuration
   */
  register(config: ComponentConfigPublic): void;
  
  /**
   * Downgrade either a given node, an array of nodes, or a NodeList
   * @param nodes - The nodes to downgrade
   */
  downgradeElements(nodes: Node[] | NodeList): void;
}

Usage Examples:

// Upgrade all MDL components in the DOM
componentHandler.upgradeAllRegistered();

// Upgrade specific component type
componentHandler.upgradeDom('MaterialButton', 'mdl-js-button');

// Upgrade a single element
const newButton = document.querySelector('.mdl-js-button');
componentHandler.upgradeElement(newButton);

// Upgrade multiple elements
const buttons = document.querySelectorAll('.mdl-js-button');
componentHandler.upgradeElements(buttons);

// Register callback for component upgrades
componentHandler.registerUpgradedCallback('MaterialButton', (element) => {
  console.log('Button upgraded:', element);
});

// Clean up components when removing elements
const elementToRemove = document.querySelector('.mdl-js-button');
componentHandler.downgradeElements([elementToRemove]);
elementToRemove.parentNode.removeChild(elementToRemove);

Component Registration

Register new component types with the component handler.

/**
 * Configuration for registering a new component type
 */
interface ComponentConfigPublic {
  /** Constructor function for the component */
  constructor: Function;
  /** String representation of the class name */
  classAsString: string;
  /** CSS class that identifies elements of this component type */
  cssClass: string;
  /** Whether the component should be accessible as a widget (default: true) */
  widget?: boolean;
}

/**
 * Internal configuration structure (for reference)
 */
interface ComponentConfig {
  classConstructor: Function;
  className: string;
  cssClass: string;
  widget: boolean;
  callbacks: Array<(element: HTMLElement) => void>;
}

Usage Examples:

// Register a custom component
function MyCustomComponent(element) {
  this.element_ = element;
  this.init();
}

MyCustomComponent.prototype.init = function() {
  // Component initialization logic
};

MyCustomComponent.prototype.myMethod = function() {
  // Custom component method
};

// Register with component handler
componentHandler.register({
  constructor: MyCustomComponent,
  classAsString: 'MyCustomComponent',
  cssClass: 'my-js-component',
  widget: true
});

// Now elements with 'my-js-component' class will be automatically upgraded

Component Events

Components emit events during their lifecycle that can be listened to for custom behavior.

/**
 * Event fired before a component is upgraded
 * Can be cancelled by calling preventDefault()
 */
interface MDLComponentUpgradingEvent extends CustomEvent {
  type: 'mdl-componentupgrading';
  bubbles: true;
  cancelable: true;
}

/**
 * Event fired after a component has been upgraded
 */
interface MDLComponentUpgradedEvent extends CustomEvent {
  type: 'mdl-componentupgraded';
  bubbles: true;
  cancelable: false;
}

/**
 * Event fired after a component has been downgraded
 */
interface MDLComponentDowngradedEvent extends CustomEvent {
  type: 'mdl-componentdowngraded';
  bubbles: true;
  cancelable: false;
}

Usage Examples:

// Listen for component upgrade events
document.addEventListener('mdl-componentupgrading', (event) => {
  console.log('Component about to upgrade:', event.target);
  
  // Cancel upgrade if needed
  if (shouldCancelUpgrade(event.target)) {
    event.preventDefault();
  }
});

document.addEventListener('mdl-componentupgraded', (event) => {
  console.log('Component upgraded:', event.target);
  
  // Perform post-upgrade actions
  setupCustomBehavior(event.target);
});

document.addEventListener('mdl-componentdowngraded', (event) => {
  console.log('Component downgraded:', event.target);
  
  // Clean up any custom behavior
  cleanupCustomBehavior(event.target);
});

Component Instance Management

Access and manage component instances on upgraded elements.

/**
 * Component instance structure (for widget components)
 */
interface Component {
  /** The DOM element this component is attached to */
  element_: HTMLElement;
  /** The component class name */
  className: string;
  /** String representation of the class */
  classAsString: string;
  /** CSS class that identifies this component type */
  cssClass: string;
  /** Widget identifier */
  widget: string;
}

Usage Examples:

// Access widget component instances
const buttonElement = document.querySelector('.mdl-js-button');
const buttonInstance = buttonElement.MaterialButton;

if (buttonInstance) {
  // Use component methods
  buttonInstance.disable();
}

// Check if element has been upgraded
const textfieldElement = document.querySelector('.mdl-js-textfield');
if (textfieldElement.MaterialTextfield) {
  console.log('Textfield is already upgraded');
  textfieldElement.MaterialTextfield.checkValidity();
} else {
  console.log('Textfield needs to be upgraded');
  componentHandler.upgradeElement(textfieldElement);
}

// List all upgraded components on an element
const upgradedList = element.getAttribute('data-upgraded');
console.log('Upgraded components:', upgradedList ? upgradedList.split(',') : []);

Error Handling

Handle errors that may occur during component management operations.

// Component upgrade errors
try {
  componentHandler.upgradeElement(invalidElement);
} catch (error) {
  if (error.message.includes('Invalid argument provided')) {
    console.error('Element is not a valid DOM element');
  } else if (error.message.includes('Unable to find a registered component')) {
    console.error('Component class not registered');
  } else {
    console.error('Unknown upgrade error:', error);
  }
}

// Registration errors
try {
  componentHandler.register({
    constructor: MyComponent,
    classAsString: 'ExistingComponent', // This will throw if already registered
    cssClass: 'my-component'
  });
} catch (error) {
  if (error.message.includes('already been registered')) {
    console.error('Component already registered');
  }
}

Best Practices

Dynamic Content

When adding MDL components dynamically:

// Create element with MDL classes
const dynamicElement = document.createElement('button');
dynamicElement.className = 'mdl-button mdl-js-button mdl-button--raised';
dynamicElement.textContent = 'Dynamic Button';

// Add to DOM first
document.body.appendChild(dynamicElement);

// Then upgrade
componentHandler.upgradeElement(dynamicElement);

// For multiple elements
const elements = [element1, element2, element3];
elements.forEach(el => document.body.appendChild(el));
componentHandler.upgradeElements(elements);

Memory Management

Clean up components when removing elements:

// Before removing elements from DOM
const elementToRemove = document.querySelector('.mdl-js-button');
componentHandler.downgradeElements([elementToRemove]);
elementToRemove.parentNode.removeChild(elementToRemove);

// For single page applications
function cleanupPage() {
  const allMDLElements = document.querySelectorAll('[data-upgraded]');
  componentHandler.downgradeElements(allMDLElements);
}

Performance

Optimize component upgrades:

// Batch upgrades when possible
const newElements = [];
for (let i = 0; i < 10; i++) {
  const el = createMDLElement();
  container.appendChild(el);
  newElements.push(el);
}
componentHandler.upgradeElements(newElements);

// Use specific component types when known
componentHandler.upgradeDom('MaterialButton', 'mdl-js-button');

docs

component-management.md

data-display-components.md

feedback-components.md

form-components.md

index.md

layout-components.md

navigation-components.md

visual-effects.md

tile.json