Lightning Web Components – Real-Time LWC Scenarios Questions

Real-world LWC development requires solving complex problems and implementing advanced patterns that go beyond basic component creation. These questions cover performance optimization, infinite scrolling, real-time data updates, complex form handling, dynamic component creation, and integration with external systems. Understanding these scenarios will help you tackle challenging requirements and build enterprise-grade LWC applications.

Real-Time LWC Scenarios - Q&A

  1. Q1. How would you implement a high-performance data table with 10,000+ records?
    Ans: Virtual scrolling pattern:
    import { LightningElement, api } from 'lwc';
                  
    export default class VirtualDataTable extends LightningElement {
      @api records = [];
      visibleRecords = [];
      rowHeight = 40;
      visibleRowCount = 15;
      scrollTop = 0;
      
      get totalHeight() {
        return this.records.length * this.rowHeight;
      }
      
      get visibleStartIndex() {
        return Math.floor(this.scrollTop / this.rowHeight);
      }
      
      get visibleEndIndex() {
        return Math.min(
          this.visibleStartIndex + this.visibleRowCount,
          this.records.length
        );
      }
      
      get offsetY() {
        return this.visibleStartIndex * this.rowHeight;
      }
      
      renderedCallback() {
        this.updateVisibleRecords();
      }
      
      handleScroll(event) {
        this.scrollTop = event.target.scrollTop;
        this.updateVisibleRecords();
      }
      
      updateVisibleRecords() {
        this.visibleRecords = this.records.slice(
          this.visibleStartIndex,
          this.visibleEndIndex
        );
      }
    }
  2. Q2. How would you implement infinite scrolling in LWC?
    Ans: Infinite scroll implementation:
    import { LightningElement, track } from 'lwc';
    import getRecords from '@salesforce/apex/RecordController.getRecords';
    
    export default class InfiniteScroll extends LightningElement {
      @track records = [];
      isLoading = false;
      currentPage = 1;
      pageSize = 20;
      hasMore = true;
      
      connectedCallback() {
        this.loadRecords();
        this.setupScrollListener();
      }
      
      setupScrollListener() {
        const container = this.template.querySelector('.container');
        container.addEventListener('scroll', this.handleScroll.bind(this));
      }
      
      async handleScroll(event) {
        const { scrollTop, scrollHeight, clientHeight } = event.target;
        
        // Check if user scrolled to bottom
        if (scrollTop + clientHeight >= scrollHeight - 5 && !this.isLoading && this.hasMore) {
          this.loadMoreRecords();
        }
      }
      
      async loadRecords() {
        try {
          this.isLoading = true;
          const newRecords = await getRecords({
            page: this.currentPage,
            pageSize: this.pageSize
          });
          
          this.records = [...this.records, ...newRecords];
          this.hasMore = newRecords.length === this.pageSize;
          this.currentPage++;
        } catch (error) {
          console.error('Error loading records:', error);
        } finally {
          this.isLoading = false;
        }
      }
      
      loadMoreRecords() {
        this.loadRecords();
      }
    }
  3. Q3. How would you implement real-time data updates using Platform Events?
    Ans: Real-time updates with Platform Events:
    import { LightningElement, track } from 'lwc';
    import { subscribe, unsubscribe, onError } from 'lightning/empApi';
    import { ShowToastEvent } from 'lightning/platformShowToastEvent';
    
    export default class RealTimeUpdates extends LightningElement {
      @track records = [];
      subscription = {};
      channelName = '/event/RecordUpdateEvent__e';
      
      connectedCallback() {
        this.handleSubscribe();
      }
      
      handleSubscribe() {
        const messageCallback = (response) => {
          const payload = response.data.payload;
          this.updateRecordInList(payload);
          
          // Show toast notification
          this.dispatchEvent(
            new ShowToastEvent({
              title: 'Record Updated',
              message: `Record ${payload.RecordId__c} was updated`,
              variant: 'info'
            })
          );
        };
        
        subscribe(this.channelName, -1, messageCallback).then((response) => {
          this.subscription = response;
        });
      }
      
      updateRecordInList(payload) {
        // Update the record in the list
        this.records = this.records.map(record => {
          if (record.Id === payload.RecordId__c) {
            return { ...record, ...payload.Fields__c };
          }
          return record;
        });
      }
      
      disconnectedCallback() {
        unsubscribe(this.subscription);
      }
    }
  4. Q4. How would you implement a complex form with dynamic validation?
    Ans: Dynamic form validation:
    import { LightningElement, track } from 'lwc';
    
    export default class DynamicForm extends LightningElement {
      @track formData = {
        firstName: '',
        lastName: '',
        email: '',
        age: '',
        subscribe: false
      };
      
      @track errors = {};
      
      validationRules = {
        firstName: [
          { required: true, message: 'First name is required' },
          { pattern: /^[a-zA-Z]+$/, message: 'First name must contain only letters' }
        ],
        lastName: [
          { required: true, message: 'Last name is required' }
        ],
        email: [
          { required: true, message: 'Email is required' },
          { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email format' }
        ],
        age: [
          { required: true, message: 'Age is required' },
          { min: 18, message: 'Must be at least 18 years old' },
          { max: 120, message: 'Must be less than 120 years old' }
        ]
      };
      
      handleInputChange(event) {
        const field = event.target.name;
        const value = event.target.value;
        
        this.formData[field] = value;
        
        // Validate field on change
        this.validateField(field, value);
      }
      
      validateField(field, value) {
        const rules = this.validationRules[field];
        if (!rules) return;
        
        for (const rule of rules) {
          if (rule.required && !value) {
            this.errors[field] = rule.message;
            return;
          }
          
          if (rule.pattern && value && !rule.pattern.test(value)) {
            this.errors[field] = rule.message;
            return;
          }
          
          if (rule.min && value < rule.min) {
            this.errors[field] = rule.message;
            return;
          }
          
          if (rule.max && value > rule.max) {
            this.errors[field] = rule.message;
            return;
          }
        }
        
        // Clear error if validation passes
        delete this.errors[field];
      }
      
      validateForm() {
        let isValid = true;
        
        // Validate all fields
        Object.keys(this.validationRules).forEach(field => {
          this.validateField(field, this.formData[field]);
          if (this.errors[field]) {
            isValid = false;
          }
        });
        
        return isValid;
      }
      
      handleSubmit() {
        if (this.validateForm()) {
          // Submit form
          console.log('Form submitted:', this.formData);
        } else {
          console.log('Form has errors:', this.errors);
        }
      }
    }
  5. Q5. How would you implement dynamic component creation in LWC?
    Ans: Dynamic component creation:
    import { LightningElement } from 'lwc';
    import { createElement } from 'lwc';
    
    // Import components dynamically
    import DynamicComponentA from 'c/dynamicComponentA';
    import DynamicComponentB from 'c/dynamicComponentB';
    
    export default class DynamicComponentCreator extends LightningElement {
      currentComponent = null;
      
      createComponent(componentType, props = {}) {
        let ComponentConstructor;
        
        switch (componentType) {
          case 'A':
            ComponentConstructor = DynamicComponentA;
            break;
          case 'B':
            ComponentConstructor = DynamicComponentB;
            break;
          default:
            throw new Error('Unknown component type');
        }
        
        // Create component instance
        const element = createElement('c-dynamic-component', {
          is: ComponentConstructor
        });
        
        // Set properties
        Object.assign(element, props);
        
        // Add event listeners
        element.addEventListener('customEvent', this.handleCustomEvent.bind(this));
        
        return element;
      }
      
      handleCustomEvent(event) {
        console.log('Custom event received:', event.detail);
      }
      
      renderComponent(componentType, props = {}) {
        // Clear previous component
        if (this.currentComponent) {
          this.template.querySelector('.container').removeChild(this.currentComponent);
        }
        
        // Create new component
        this.currentComponent = this.createComponent(componentType, props);
        
        // Add to DOM
        this.template.querySelector('.container').appendChild(this.currentComponent);
      }
      
      renderComponentA() {
        this.renderComponent('A', { message: 'Hello from Component A' });
      }
      
      renderComponentB() {
        this.renderComponent('B', { data: [1, 2, 3, 4, 5] });
      }
    }
  6. Q6. How would you implement a search-as-you-type feature with debouncing?
    Ans: Debounced search implementation:
    import { LightningElement, track } from 'lwc';
    import searchRecords from '@salesforce/apex/RecordController.searchRecords';
    
    export default class SearchAsYouType extends LightningElement {
      @track searchResults = [];
      @track isLoading = false;
      @track searchTerm = '';
      searchTimeout;
      
      handleSearchChange(event) {
        const searchTerm = event.target.value;
        this.searchTerm = searchTerm;
        
        // Clear previous timeout
        if (this.searchTimeout) {
          clearTimeout(this.searchTimeout);
        }
        
        // Set new timeout
        this.searchTimeout = setTimeout(() => {
          this.performSearch(searchTerm);
        }, 300); // 300ms delay
      }
      
      async performSearch(searchTerm) {
        if (!searchTerm) {
          this.searchResults = [];
          return;
        }
        
        try {
          this.isLoading = true;
          this.searchResults = await searchRecords({ searchTerm });
        } catch (error) {
          console.error('Search error:', error);
          this.searchResults = [];
        } finally {
          this.isLoading = false;
        }
      }
      
      // Cancel search if component is destroyed
      disconnectedCallback() {
        if (this.searchTimeout) {
          clearTimeout(this.searchTimeout);
        }
      }
    }
  7. Q7. How would you implement a drag-and-drop file uploader?
    Ans: Drag-and-drop file uploader:
    import { LightningElement, track } from 'lwc';
    import { ShowToastEvent } from 'lightning/platformShowToastEvent';
    
    export default class DragDropUploader extends LightningElement {
      @track isDragOver = false;
      @track uploadedFiles = [];
      
      handleDragEnter(event) {
        event.preventDefault();
        this.isDragOver = true;
      }
      
      handleDragOver(event) {
        event.preventDefault();
      }
      
      handleDragLeave(event) {
        event.preventDefault();
        this.isDragOver = false;
      }
      
      handleDrop(event) {
        event.preventDefault();
        this.isDragOver = false;
        
        const files = event.dataTransfer.files;
        this.handleFiles(files);
      }
      
      handleFileInputChange(event) {
        const files = event.target.files;
        this.handleFiles(files);
      }
      
      handleFiles(files) {
        for (let i = 0; i < files.length; i++) {
          const file = files[i];
          
          // Validate file type and size
          if (this.validateFile(file)) {
            this.uploadedFiles.push({
              name: file.name,
              size: file.size,
              type: file.type,
              file: file
            });
          }
        }
      }
      
      validateFile(file) {
        const maxFileSize = 5 * 1024 * 1024; // 5MB
        const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
        
        if (file.size > maxFileSize) {
          this.dispatchEvent(
            new ShowToastEvent({
              title: 'File too large',
              message: `${file.name} exceeds 5MB limit`,
              variant: 'error'
            })
          );
          return false;
        }
        
        if (!allowedTypes.includes(file.type)) {
          this.dispatchEvent(
            new ShowToastEvent({
              title: 'Invalid file type',
              message: `${file.name} is not a supported file type`,
              variant: 'error'
            })
          );
          return false;
        }
        
        return true;
      }
      
      removeFile(event) {
        const index = event.target.dataset.index;
        this.uploadedFiles.splice(index, 1);
      }
      
      uploadFiles() {
        // Implement file upload logic
        this.uploadedFiles.forEach(fileObj => {
          this.uploadFile(fileObj.file);
        });
      }
      
      async uploadFile(file) {
        // Implementation for uploading file to Salesforce
        // This would typically use lightning-file-upload or a custom Apex method
      }
    }
  8. Q8. How would you implement a responsive navigation menu?
    Ans: Responsive navigation implementation:
    import { LightningElement, track } from 'lwc';
    
    export default class ResponsiveNavigation extends LightningElement {
      @track isMenuOpen = false;
      @track isMobile = false;
      
      connectedCallback() {
        this.checkScreenSize();
        window.addEventListener('resize', this.checkScreenSize.bind(this));
      }
      
      checkScreenSize() {
        this.isMobile = window.innerWidth < 768;
      }
      
      toggleMenu() {
        this.isMenuOpen = !this.isMenuOpen;
      }
      
      closeMenu() {
        this.isMenuOpen = false;
      }
      
      handleNavigation(event) {
        const page = event.target.dataset.page;
        
        // Navigate to page
        this.navigateToPage(page);
        
        // Close menu on mobile
        if (this.isMobile) {
          this.closeMenu();
        }
      }
      
      navigateToPage(page) {
        // Implementation for navigation
        console.log('Navigating to:', page);
      }
      
      get menuClass() {
        return `slds-nav-vertical ${this.isMenuOpen ? 'slds-is-expanded' : ''}`;
      }
      
      get menuButtonClass() {
        return `slds-button slds-button_icon slds-button_icon-container ${
          this.isMenuOpen ? 'slds-is-selected' : ''
        }`;
      }
      
      disconnectedCallback() {
        window.removeEventListener('resize', this.checkScreenSize);
      }
    }
  9. Q9. How would you implement a complex charting solution in LWC?
    Ans: Charting implementation with Chart.js:
    import { LightningElement, api, track } from 'lwc';
    import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
    import chartjs from '@salesforce/resourceUrl/chartJs';
    
    export default class ChartComponent extends LightningElement {
      @api chartType = 'bar';
      @api chartData = [];
      @api chartLabels = [];
      @track isChartJsLoaded = false;
      
      chart;
      
      renderedCallback() {
        if (this.isChartJsLoaded) {
          this.renderChart();
        } else {
          this.loadChartJs();
        }
      }
      
      async loadChartJs() {
        try {
          await loadScript(this, chartjs + '/Chart.min.js');
          await loadStyle(this, chartjs + '/Chart.min.css');
          this.isChartJsLoaded = true;
          this.renderChart();
        } catch (error) {
          console.error('Error loading Chart.js:', error);
        }
      }
      
      renderChart() {
        const canvas = this.template.querySelector('canvas');
        if (!canvas) return;
        
        const ctx = canvas.getContext('2d');
        
        // Destroy existing chart if it exists
        if (this.chart) {
          this.chart.destroy();
        }
        
        // Create new chart
        this.chart = new Chart(ctx, {
          type: this.chartType,
          data: {
            labels: this.chartLabels,
            datasets: [{
              label: 'Data',
              data: this.chartData,
              backgroundColor: 'rgba(54, 162, 235, 0.2)',
              borderColor: 'rgba(54, 162, 235, 1)',
              borderWidth: 1
            }]
          },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            scales: {
              y: {
                beginAtZero: true
              }
            }
          }
        });
      }
      
      @api
      updateChartData(newData, newLabels) {
        this.chartData = newData;
        this.chartLabels = newLabels;
        
        if (this.chart) {
          this.chart.data.datasets[0].data = newData;
          this.chart.data.labels = newLabels;
          this.chart.update();
        }
      }
      
      disconnectedCallback() {
        if (this.chart) {
          this.chart.destroy();
        }
      }
    }
  10. Q10. How would you implement a multi-step form wizard?
    Ans: Multi-step form wizard:
    import { LightningElement, track } from 'lwc';
    
    export default class MultiStepForm extends LightningElement {
      @track currentStep = 1;
      @track formData = {
        step1: {},
        step2: {},
        step3: {}
      };
      
      steps = [
        { id: 1, name: 'Personal Info', completed: false },
        { id: 2, name: 'Contact Info', completed: false },
        { id: 3, name: 'Confirmation', completed: false }
      ];
      
      get progress() {
        return (this.currentStep / this.steps.length) * 100;
      }
      
      get isLastStep() {
        return this.currentStep === this.steps.length;
      }
      
      get isFirstStep() {
        return this.currentStep === 1;
      }
      
      nextStep() {
        if (this.currentStep < this.steps.length) {
          this.markStepAsCompleted(this.currentStep);
          this.currentStep++;
        }
      }
      
      previousStep() {
        if (this.currentStep > 1) {
          this.currentStep--;
        }
      }
      
      markStepAsCompleted(stepId) {
        const step = this.steps.find(step => step.id === stepId);
        if (step) {
          step.completed = true;
        }
      }
      
      handleInputChange(event) {
        const field = event.target.name;
        const value = event.target.value;
        
        // Store data in current step
        this.formData[`step${this.currentStep}`][field] = value;
      }
      
      handleSubmit() {
        // Submit all form data
        console.log('Form submitted:', this.formData);
        
        // Reset form
        this.resetForm();
      }
      
      resetForm() {
        this.currentStep = 1;
        this.formData = {
          step1: {},
          step2: {},
          step3: {}
        };
        
        // Reset step completion status
        this.steps.forEach(step => {
          step.completed = false;
        });
      }
      
      get step1Class() {
        return this.currentStep === 1 ? 'slds-show' : 'slds-hide';
      }
      
      get step2Class() {
        return this.currentStep === 2 ? 'slds-show' : 'slds-hide';
      }
      
      get step3Class() {
        return this.currentStep === 3 ? 'slds-show' : 'slds-hide';
      }
    }

Back to LWC Home