प्रतिनिधि इंटरव्यू विषय

Frontend Interview: एक एक्सेसिबल Modal Dialog कैसे बनाएं?

फ्रंटएंडमध्यम
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

एक पुनः प्रयोज्य (reusable) एक्सेसिबल मोडल डायलॉग बनाएं जो एक बटन से खुलता हो, अपने पीछे के पेज को विज़ुअली और व्यावहारिक रूप से ब्लॉक करता हो, एक उपयोगी एक्सेसिबल नाम दिखाता हो, कीबोर्ड फ़ोकस को सक्रिय डायलॉग के भीतर रखता हो, एक स्पष्ट कंट्रोल और Escape के माध्यम से बंद होता हो, और फ़ोकस को सही जगह वापस भेजता हो। इनिशियल-फ़ोकस नीति, नेटिव बनाम कस्टम इम्प्लीमेंटेशन, विनाशकारी पुष्टिकरण (destructive confirmations), स्टैक्ड डायलॉग्स, फ़्रेमवर्क लाइफ़साइकिल जोखिम और टेस्टिंग की व्याख्या करें।

प्रांप्ट और लागू संदर्भ

फ़्रंटएंड UI कोडिंग इंटरव्यू के लिए एक पुनः प्रयोज्य मोडल डायलॉग बनाएं। कॉलर एक शीर्षक, वैकल्पिक संक्षिप्त विवरण, बॉडी कंटेंट, ओपन स्टेट, और पुष्टि व बंद करने के कॉलबैक प्रदान करता है। डायलॉग को माउस, टच, कीबोर्ड और सहायक-तकनीक (assistive-technology) उपयोगकर्ताओं का समर्थन करना चाहिए। विज़ुअल सेंटरिंग और एक डिम्ड बैकड्रॉप आवश्यक हैं, लेकिन मुख्य समस्या व्यवहार की है: सक्रिय डायलॉग के बाहर की सामग्री अनुपलब्ध होनी चाहिए, डायलॉग का एक उपयोगी नाम होना चाहिए, फ़ोकस इसमें प्रवेश करे और इसके भीतर ही रहे, प्रत्येक उपयोगकर्ता के पास इसे बंद करने का एक स्पष्ट तरीका हो, और उसके बाद फ़ोकस एक तार्किक स्थान पर वापस लौटे।

मान लें कि वर्तमान एवरग्रीन ब्राउज़र नेटिव डायलॉग API का समर्थन करते हैं। यह भी स्पष्ट करें कि यह कॉन्ट्रैक्ट तब कैसे लागू किया जाएगा जब कोई इंटरव्यूअर स्पष्ट रूप से नेटिव एलिमेंट के उपयोग पर रोक लगाता है, किसी एम्बेडेड वेबव्यू में समर्थन की कमी होती है, या किसी मौजूदा कंपोनेंट लाइब्रेरी के पास पहले से ही एक परीक्षित कस्टम प्रिमिटिव मौजूद है। इस पुनः प्रयोज्य यूनिट को किसी एक इनिशियल-फ़ोकस टारगेट को हार्ड-कोड नहीं करना चाहिए क्योंकि एक फ़ॉर्म, एक लंबा सूचनात्मक डायलॉग, और एक अपरिवर्तनीय डिलीट पुष्टिकरण को अलग-अलग विकल्पों की आवश्यकता होती है।

इस इम्प्लीमेंटेशन में एप्लिकेशन-विशिष्ट डेटा फ़ेचिंग, एनिमेशन डिज़ाइन, या एक पूर्ण मोडल मैनेजर शामिल नहीं है। वे फ़ॉलो-अप प्रश्न बन जाते हैं। स्वीकृति मानदंड अवलोकनीय (observable) हैं: कीबोर्ड एक्टिवेशन, फ़ोकस प्लेसमेंट, फ़ोकस कंटेनमेंट, एक्सेसिबल नेमिंग, क्लोज़ बिहेवियर, फ़ोकस रेस्टोरेशन, लेयरिंग, और री-रेंडर व अनमाउंट के दौरान स्थिर व्यवहार।

इंटरव्यूअर क्या मूल्यांकन करता है

पहला संकेत यह है कि क्या उम्मीदवार "मोडल" को एक व्यावहारिक अनुबंध (behavioral contract) के रूप में परिभाषित करता है। उच्च स्टैकिंग मान वाला एक सेंटर्ड पैनल केवल एक ओवरले होता है। एक वास्तविक मोडल शेष दस्तावेज़ को इनर्ट (inert) बनाता है, टैब अनुक्रम को समाहित करता है, डायलॉग सिमेंटिक्स प्रदर्शित करता है, और पूरे फ़ोकस लाइफ़साइकिल का प्रबंधन करता है। बाहर की सामग्री को अनुपलब्ध बनाए बिना केवल एक ARIA विशेषता जोड़ने से एक भ्रामक एक्सेसिबिलिटी ट्री बनता है।

दूसरा संकेत प्लेटफ़ॉर्म का निर्णय है। showModal() के साथ खोला गया नेटिव डायलॉग एलिमेंट ब्राउज़र की टॉप लेयर में प्रवेश करता है, एक बैकड्रॉप बनाता है, उसी दस्तावेज़ के अन्य एलिमेंट्स को इनर्ट बनाता है, और मोडल कीबोर्ड व्यवहार प्रदान करता है। इसे show() के साथ खोलना या इसकी open विशेषता सेट करना नॉन-मोडल होता है। एक मजबूत उत्तर नेटिव प्रिमिटिव का उपयोग करता है जब उत्पाद का ब्राउज़र अनुबंध इसकी अनुमति देता है, साथ ही उन सभी इनवेरिएंट्स को बताने में सक्षम होता है जिन्हें एक कस्टम इम्प्लीमेंटेशन को पुन: उत्पन्न करना चाहिए।

तीसरा संकेत रटे-रटाए "पहले बटन पर फ़ोकस करें" नियम के बजाय फ़ोकस नीति है। एक छोटा फ़ॉर्म अपने पहले अमान्य या प्राथमिक फ़ील्ड पर फ़ोकस कर सकता है। एक लंबे दस्तावेज़-जैसे डायलॉग को अक्सर एक प्रोग्रामैटिक फ़ोकस टारगेट के साथ एक स्थिर शीर्षक पर फ़ोकस करना चाहिए ताकि शुरुआत और सिमेंटिक संरचना उपलब्ध रहे। एक अपरिवर्तनीय पुष्टिकरण को शुरू में सबसे कम विनाशकारी क्रिया पर फ़ोकस करना चाहिए। बंद होने पर, फ़ोकस आमतौर पर ओपनर पर वापस लौटता है; यदि वह एलिमेंट हटा दिया गया था, तो कॉलर को अगले तार्किक कार्य आइटम का चयन करना चाहिए।

चौथा संकेत फ़्रेमवर्क लाइफ़साइकिल की शुद्धता है। अनिवार्य (imperative) ब्राउज़र स्थिति और घोषणात्मक (declarative) UI स्थिति में अंतर नहीं होना चाहिए। showModal() को दो बार कॉल करना, स्थिति को सिंक्रोनाइज़ करने से पहले एक खुले डायलॉग को हटाना, पैरेंट को अपडेट किए बिना इसे बंद करना, या किसी पुराने नोड पर फ़ोकस रीस्टोर करना वास्तविक बग्स का कारण बनता है। इवेंट लिसनर्स को क्लीनअप की आवश्यकता होती है, अद्वितीय लेबल्स को स्थिर रहना चाहिए, और सर्वर रेंडरिंग को रेंडर के दौरान किसी ब्राउज़र API को कॉल नहीं करना चाहिए।

अंतिम संकेत सत्यापन की गुणवत्ता है। स्वचालित एक्सेसिबिलिटी जांच छूटे हुए नाम या अमान्य विशेषताओं को पकड़ सकती है, लेकिन वे यह साबित नहीं कर सकती हैं कि इस वर्कफ़्लो के लिए फ़ोकस सही एलिमेंट पर जाता है, कि Tab और Shift+Tab समाहित रहते हैं, कि Escape उत्पाद नीति का पालन करता है, या कि ओपनर के गायब होने के बाद फ़ोकस एक तार्किक स्थान पर वापस आता है। इनके लिए कीबोर्ड और स्क्रीन-रीडर जांच की आवश्यकता होती है।

उत्तर देने से पहले स्पष्ट करने योग्य प्रश्न

  • क्या यह वास्तव में मोडल है? यदि उपयोगकर्ताओं को पेज के साथ इंटरैक्ट करना जारी रखना चाहिए, तो एक नॉन-मोडल डायलॉग, पॉपओवर, या इनलाइन पैनल का उपयोग करें। केवल इसलिए इसे मोडल लेबल न करें क्योंकि यह सामग्री के ऊपर तैरता है।
  • क्या मैं नेटिव डायलॉग एलिमेंट का उपयोग कर सकता हूँ? यदि हाँ, तो showModal() का उपयोग करें और इसके डिफ़ॉल्ट व्यवहार को बनाए रखें। यदि नहीं, तो सिमेंटिक्स, बाहरी इनर्टनेस, फ़ोकस कंटेनमेंट, Escape और रेस्टोरेशन को स्पष्ट रूप से लागू करें।
  • अंदर कौन सी सामग्री दिखाई देती है? एक साधारण फ़ॉर्म, एक लंबा संरचित दस्तावेज़, और एक अलर्ट के लिए अलग-अलग एक्सेसिबल विवरण और इनिशियल-फ़ोकस विकल्पों की आवश्यकता होती है।
  • क्या ऑपरेशन को पूर्ववत (reversed) किया जा सकता है? डिलीट करने या भुगतान के लिए, Cancel या अन्य कम से कम विनाशकारी नियंत्रण पर फ़ोकस करें। एक नियमित निरंतरता डायलॉग के लिए, संभावित अगली कार्रवाई उपयुक्त हो सकती है।
  • यह कैसे बंद हो सकता है? हमेशा एक दृश्यमान क्लोज़ या कैंसल कंट्रोल प्रदान करें। Escape, बैकड्रॉप क्लिक, सबमिट सफलता, और क्या बिना सहेजे गए इनपुट के लिए पुष्टिकरण चरण की आवश्यकता है, इसे स्पष्ट करें।
  • बंद होने के बाद किसे फ़ोकस प्राप्त होना चाहिए? आमतौर पर ओपनर को। यदि निर्माण उस नोड को हटा देता है या बदल देता है, तो कंपोनेंट लिखने से पहले एक स्थिर तार्किक उत्तराधिकारी की पहचान करें।
  • क्या डायलॉग स्टैक हो सकते हैं? एक सक्रिय मोडल को प्राथमिकता दें। यदि स्टैकिंग आवश्यक है, तो केवल शीर्ष डायलॉग ही डिस्मिसल को संभालता है, और इसे बंद करने से इसके नीचे के डायलॉग के अंदर फ़ोकस रीस्टोर हो जाता है।
  • दायरे में कौन से ब्राउज़र और सहायक तकनीकें हैं? यह तय करता है कि नेटिव एलिमेंट पर्याप्त है, एक कम्पैटिबिलिटी लेयर की आवश्यकता है, या इसे एक स्थापित परीक्षित प्रिमिटिव द्वारा प्रतिस्थापित किया जाना चाहिए।

30-सेकंड का उत्तर फ़्रेमवर्क

"मैं छह इनवेरिएंट्स को परिभाषित करूँगा: एक एक्सेसिबल नाम, इनर्ट बैकग्राउंड, सोच-समझकर चुना गया इनिशियल फ़ोकस, एक समाहित टैब अनुक्रम, स्पष्ट और Escape डिस्मिसल, और तार्किक फ़ोकस रेस्टोरेशन। वर्तमान ब्राउज़रों पर मैं टॉप लेयर, बैकड्रॉप, इनर्टनेस, और कोर फ़ोकस व्यवहार के लिए showModal() के साथ नेटिव डायलॉग एलिमेंट का उपयोग करूँगा। इनिशियल फ़ोकस कार्य का अनुसरण करता है: लंबी सामग्री के लिए एक शीर्षक, फ़ॉर्म के लिए प्रासंगिक फ़ील्ड, और अपरिवर्तनीय कार्रवाई के लिए Cancel। React में मैं नियंत्रित स्थिति (controlled state) को गार्डेड ओपन और क्लोज़ इफ़ेक्ट्स के साथ सिंक्रोनाइज़ करूँगा, सीधे cancel को सुनूँगा, और कीबोर्ड ओपनिंग, दोनों टैब दिशाओं, डिस्मिसल, स्क्रीन-रीडर नेमिंग, फ़ोकस रेस्टोरेशन, री-रेंडर, और स्टैक्ड डायलॉग्स को सत्यापित करूँगा।"

चरण-दर-चरण विस्तृत विवरण (Step-by-Step Deep Dive)

उन इनवेरिएंट्स से शुरुआत करें जो React, CSS, या नेटिव एलिमेंट से स्वतंत्र हैं:

text
OPEN
  exactly one active modal owns interaction
  outside content is visually obscured and behaviorally inert
  dialog has an accessible name from a visible title
  focus is inside the dialog on a purposefully selected target

WHILE OPEN
  Tab and Shift+Tab cannot enter the background document
  visible close or cancel control is reachable
  only the top modal handles a close request

CLOSE
  parent open state and browser dialog state agree
  focus returns to the opener if it exists
  otherwise focus moves to a predefined logical successor

इसके बाद प्रिमिटिव चुनें। वर्तमान ब्राउज़र अनुबंध के लिए नेटिव डायलॉग डिफ़ॉल्ट है। showModal() को कॉल करने से यह टॉप लेयर में चला जाता है, इसे एक बैकड्रॉप मिलता है, और इसके दस्तावेज़ में अन्य सामग्री इनर्ट हो जाती है। यह प्रत्येक फ़ोकस करने योग्य एलिमेंट पर मैन्युअली जाने, एप्लिकेशन रूट्स में aria-hidden सेट करने और स्टैकिंग संदर्भों से लड़ने से बचाता है। show() को कॉल करने या open सेट करने से एक नॉन-मोडल डायलॉग बनता है, इसलिए वे इंटरचेंजेबल शॉर्टकट नहीं हैं।

एक कस्टम डायलॉग तब मान्य रहता है जब साक्षात्कार में नेटिव एलिमेंट निषिद्ध हो या उत्पाद पहले से ही एक परिपक्व कंपोनेंट प्रिमिटिव का उपयोग करता हो। इसे डायलॉग सिमेंटिक्स और एक एक्सेसिबल नाम के साथ एक कंटेनर रेंडर करना चाहिए, मोडल सिमेंटिक्स केवल तभी सेट करना चाहिए जब बाहरी इंटरैक्शन वास्तव में अवरुद्ध हो, सभी बैकग्राउंड रूट्स को इनर्ट बनाना चाहिए, फ़ोकस को समाहित करना चाहिए, Escape को संभालना चाहिए, फ़ोकस को रीस्टोर करना चाहिए, और एप्लिकेशन स्टैकिंग संदर्भों के ऊपर रेंडर करना चाहिए। पैनल को दस्तावेज़ की बॉडी में पोर्टल करने से क्लिपिंग और स्टैकिंग में मदद मिलती है, लेकिन केवल एक पोर्टल इनमें से कोई भी एक्सेसिबिलिटी व्यवहार प्रदान नहीं करता है।

एक इनिशियल-फ़ोकस निर्णय तालिका (decision table) का उपयोग करें:

  • एक छोटे फ़ॉर्म के लिए, उस पहले फ़ील्ड पर फ़ोकस करें जिस पर उपयोगकर्ता को कार्रवाई करनी चाहिए, विशेष रूप से वैलिडेशन के बाद एक अमान्य फ़ील्ड पर।
  • लंबे टेक्स्ट, सूचियों या तालिकाओं के लिए, प्रोग्रामैटिक फ़ोकस टारगेट के साथ शीर्षक या शुरुआत में किसी अन्य स्थिर एलिमेंट पर फ़ोकस करें। समृद्ध संरचना को एक लंबे एक्सेसिबल विवरण में समतल (flatten) न करें।
  • अपरिवर्तनीय कार्य के लिए, Cancel या कम से कम विनाशकारी कार्रवाई पर फ़ोकस करें।
  • एक साधारण पावती (acknowledgement) या निरंतरता के लिए, सबसे संभावित कार्रवाई पर फ़ोकस करें जब ऐसा करने से आकस्मिक नुकसान न हो सके।

एक्सेसिबल नाम को सामान्य रूप से दृश्यमान शीर्षक का संदर्भ देना चाहिए। एक संक्षिप्त सादे-टेक्स्ट विवरण को अलग से संदर्भित किया जा सकता है। कई पैराग्राफ़, सूचियों या तालिकाओं वाली सामग्री के लिए एकल विवरण संदर्भ को छोड़ दें ताकि सहायक-तकनीक उपयोगकर्ता उस संरचना को नेविगेट कर सकें। एक क्लोज़ आइकन को अभी भी एक एक्सेसिबल नाम की आवश्यकता होती है, और Escape समर्थित होने पर भी एक दृश्यमान क्लोज़ या कैंसल कंट्रोल मौजूद होना चाहिए।

निम्नलिखित React उदाहरण नेटिव ब्राउज़र स्थिति को नियंत्रित एप्लिकेशन स्थिति के साथ सिंक्रोनाइज़ रखता है। इसका description प्रॉप जानबूझकर एक छोटा स्ट्रिंग है; जटिल सामग्री children में जाती है और इसे एक समतल विवरण के रूप में असाइन नहीं किया जाता है।

tsx
'use client'

import { useEffect, useId, useRef, type ReactNode } from 'react'

interface AccessibleModalProps {
  open: boolean
  title: string
  description?: string
  initialFocus: 'heading' | 'cancel' | 'confirm'
  children: ReactNode
  onConfirm: () => void
  onOpenChange: (open: boolean) => void
}

export function AccessibleModal({
  open,
  title,
  description,
  initialFocus,
  children,
  onConfirm,
  onOpenChange,
}: AccessibleModalProps) {
  const dialogRef = useRef<HTMLDialogElement>(null)
  const headingRef = useRef<HTMLHeadingElement>(null)
  const cancelRef = useRef<HTMLButtonElement>(null)
  const confirmRef = useRef<HTMLButtonElement>(null)
  const titleId = useId()
  const descriptionId = useId()

  useEffect(() => {
    const dialog = dialogRef.current
    if (!dialog) return

    if (open && !dialog.open) {
      dialog.showModal()
      const target =
        initialFocus === 'confirm'
          ? confirmRef.current
          : initialFocus === 'cancel'
            ? cancelRef.current
            : headingRef.current
      target?.focus()
    } else if (!open && dialog.open) {
      dialog.close()
    }
  }, [initialFocus, open])

  useEffect(() => {
    const dialog = dialogRef.current
    if (!dialog) return

    const handleCancel = (event: Event) => {
      event.preventDefault()
      onOpenChange(false)
    }
    const handleClose = () => {
      if (open) onOpenChange(false)
    }

    dialog.addEventListener('cancel', handleCancel)
    dialog.addEventListener('close', handleClose)
    return () => {
      dialog.removeEventListener('cancel', handleCancel)
      dialog.removeEventListener('close', handleClose)
    }
  }, [onOpenChange, open])

  return (
    <dialog
      ref={dialogRef}
      aria-labelledby={titleId}
      aria-describedby={description ? descriptionId : undefined}
    >
      <h2 ref={headingRef} id={titleId} tabIndex={-1}>
        {title}
      </h2>
      {description ? <p id={descriptionId}>{description}</p> : null}
      {children}
      <div>
        <button ref={cancelRef} type="button" onClick={() => onOpenChange(false)}>
          Cancel
        </button>
        <button ref={confirmRef} type="button" onClick={onConfirm}>
          Confirm
        </button>
      </div>
    </dialog>
  )
}

dialog.open के चारों ओर लगे गार्ड री-रेंडर के दौरान डुप्लिकेट अनिवार्य कॉल को रोकते हैं। प्रत्यक्ष cancel लिसनर महत्वपूर्ण है क्योंकि इवेंट कैंसल करने योग्य है और बब्बल नहीं करता है। इसके डिफ़ॉल्ट क्लोज़ को रोकने से पहले नियंत्रित स्थिति बदल सकती है; अगला प्रभाव नेटिव डायलॉग को बंद कर देता है। यदि कोई अन्य नेटिव क्लोज़ पाथ चलता है तो close लिसनर स्थिति को भी सुधारता है। ब्राउज़र API इफ़ेक्ट्स के अंदर रहते हैं, इसलिए सर्वर रेंडरिंग केवल मार्कअप उत्सर्जित करता है।

डिस्मिसल नीति को स्पष्ट रखें। बैकड्रॉप क्लिक अपने आप Cancel के बराबर नहीं होता है। बिना सहेजे गए काम वाला फ़ॉर्म बैकड्रॉप क्लिक को अनदेखा कर सकता है, एक हल्का पिकर उन्हें स्वीकार कर सकता है, और एक अपरिवर्तनीय पुष्टिकरण को आकस्मिक पॉइंटर इवेंट से गायब नहीं होना चाहिए। यदि उत्पाद बैकड्रॉप डिस्मिसल स्वीकार करता है, तो एक परीक्षित बैकड्रॉप-क्षेत्र हिट टेस्ट का उपयोग करें और इसे उसी नियंत्रित क्लोज़ पाथ के माध्यम से रूट करें। केवल एक इवेंट-टारगेट जांच डायलॉग पैडिंग पर क्लिक को बैकड्रॉप क्लिक समझने की गलती कर सकती है। कभी भी फ़ुल-स्क्रीन अदृश्य क्लोज़ टारगेट न बनाएं जो डायलॉग के लिए लक्षित क्लिक को चुरा ले।

नेटिव फ़ोकस रेस्टोरेशन सामान्य रूप से इनवोकिंग एलिमेंट पर वापस लौटता है। एप्लिकेशन प्रवाह केवल एक कारण से इसे ओवरराइड कर सकता है। जब एक डायलॉग एक नई पंक्ति बनाता है और "Add row" बटन को हटा देता है, तो नई पंक्ति का पहला सेल एक तार्किक गंतव्य होता है। इस नीति को कॉलर पर कैप्चर करें, क्योंकि पुनः प्रयोज्य डायलॉग यह अनुमान नहीं लगा सकता है कि आसपास के वर्कफ़्लो में क्या बदला है।

स्टैक्ड डायलॉग्स के लिए, एक डायलॉग के भीतर सामग्री बदलने को प्राथमिकता दें। यदि दूसरा मोडल अपरिहार्य है, तो एक स्टैक बनाए रखें: केवल इसकी शीर्ष प्रविष्टि Escape या बैकड्रॉप से बंद हो सकती है, बैकग्राउंड डायलॉग इनर्ट रहते हैं, और शीर्ष प्रविष्टि को बंद करने से पिछले डायलॉग के अंदर इसे खोलने वाले नियंत्रण पर फ़ोकस रीस्टोर हो जाता है। एक ग्लोबल बूलियन उस संबंध का प्रतिनिधित्व नहीं कर सकता है।

केवल रेंडर की गई विशेषताओं का ही नहीं, व्यवहार का परीक्षण करें:

text
1. Open with Enter and Space; verify focus enters the intended target.
2. Tab from the last control and Shift+Tab from the first; verify background is unreachable.
3. Press Escape; verify one top dialog closes and controlled state becomes false.
4. Use the visible close and Cancel controls with keyboard, pointer, and touch.
5. Close normally; verify focus returns to the opener.
6. Remove the opener during completion; verify focus moves to the chosen logical successor.
7. Read with a screen reader; verify one useful title and no flattened rich description.
8. Open a destructive confirmation; verify initial focus is on the least destructive action.
9. Rerender repeatedly while open; verify no duplicate-open exception or focus reset.
10. Unmount during navigation; verify no listener leak or focus jump to the document body.
11. At 200% zoom and a small viewport, verify title, controls, and scrollable content remain reachable.
12. Run automated accessibility checks, then repeat the manual focus workflow they cannot prove.

उच्च-गुणवत्ता वाला नमूना उत्तर

"मैं मोडल को एक बड़े स्टैकिंग मान वाले पैनल के रूप में नहीं, बल्कि एक फ़ोकस और इंटरैक्शन स्टेट मशीन के रूप में मानूँगा। जब यह खुलता है, तो शेष दस्तावेज़ इनर्ट हो जाना चाहिए, डायलॉग को इसके दृश्यमान शीर्षक से जुड़े नाम की आवश्यकता होती है, और फ़ोकस को कार्य से चुने गए लक्ष्य पर जाना चाहिए। खुले रहने के दौरान, कीबोर्ड नेविगेशन अंदर रहता है और एक दृश्यमान क्लोज़ या कैंसल कंट्रोल हमेशा पहुंच योग्य होता है। बंद होने पर, फ़ोकस ओपनर पर वापस आ जाता है जब तक कि वर्कफ़्लो ने इसे बदल न दिया हो, जिस स्थिति में कॉलर एक तार्किक उत्तराधिकारी की आपूर्ति करता है।

वर्तमान ब्राउज़रों के लिए मैं नेटिव डायलॉग एलिमेंट का उपयोग करूँगा और showModal() को कॉल करूँगा। इससे मुझे टॉप लेयर, बैकड्रॉप, बैकग्राउंड इनर्टनेस, और कोर मोडल फ़ोकस व्यवहार मिलता है। open सेट करना या show() को कॉल करना गैर-मोडल व्यवहार उत्पन्न करेगा, इसलिए मैं इनमें से किसी को भी विकल्प के रूप में उपयोग नहीं करूँगा। यदि अभ्यास में नेटिव एलिमेंट निषिद्ध है, तो मैं डायलॉग रोल, एक्सेसिबल नाम, वास्तविक बाहरी इनर्टनेस, फ़ोकस कंटेनमेंट, Escape हैंडलिंग, एक पोर्टल, और रेस्टोरेशन के साथ समान इनवेरिएंट्स को पुन: उत्पन्न करूँगा, नए एड-हॉक फ़ोकस-ट्रैप कोड के बजाय अधिमानतः एक मौजूदा परीक्षित प्रिमिटिव के माध्यम से।

इनिशियल फ़ोकस सामग्री पर निर्भर करता है। मैं एक छोटे फ़ॉर्म के लिए प्रासंगिक फ़ील्ड, लंबी संरचित सामग्री के लिए एक स्थिर शीर्षक, और एक अपरिवर्तनीय कार्रवाई के लिए Cancel पर फ़ोकस करूँगा। मैं एक संक्षिप्त विवरण का संदर्भ केवल तभी दूँगा जब इसे एक घोषणा के रूप में समझा जा सके; सूचियाँ और कई पैराग्राफ़ संरचना के रूप में नेविगेट करने योग्य रहते हैं।

React में मैं इफ़ेक्ट्स के अंदर showModal() और close() के साथ नियंत्रित स्थिति को सिंक्रोनाइज़ करूँगा, डुप्लिकेट कॉल से बचाव करूँगा, सीधे नॉन-बबलिंग cancel इवेंट को सुनूँगा, और क्लीनअप पर लिसनर्स को हटा दूँगा। बैकड्रॉप डिस्मिसल एक स्पष्ट उत्पाद नीति होगी। मैं कीबोर्ड ओपनिंग, दोनों टैब दिशाओं, Escape, स्पष्ट क्लोज़, स्क्रीन-रीडर नेमिंग, ट्रिगर के मौजूद होने या गायब होने पर फ़ोकस रेस्टोरेशन, बार-बार री-रेंडर, स्टैक्ड डायलॉग्स, ज़ूम, और छोटे व्यूपोर्ट्स को सत्यापित करूँगा। स्वचालित जांच उस वर्कफ़्लो की पूरक हैं लेकिन इसे प्रतिस्थापित नहीं करती हैं।"

सामान्य गलतियाँ

  • एक केंद्रित ओवरले को स्टाइल करना और इसे मोडल कहना → बैकग्राउंड कंट्रोल्स कीबोर्ड या सहायक तकनीक के लिए पहुंच योग्य रहते हैं → इनर्टनेस और फ़ोकस लाइफ़साइकिल को परिभाषित और परीक्षण करें।
  • बाहरी इंटरैक्शन को ब्लॉक किए बिना मोडल सिमेंटिक्स जोड़ना → एक्सेसिबिलिटी ट्री एक ऐसी स्थिति का वादा करता है जिसे देखने वाले पॉइंटर उपयोगकर्ता अनुभव नहीं करते हैं → मोडल सिमेंटिक्स केवल तभी सेट करें जब व्यवहार वास्तव में मोडल हो।
  • नेटिव open विशेषता को टॉगल करना → डायलॉग बिना showModal() व्यवहार के प्रदर्शित होता है → सही मोडल विधि का उपयोग करें और इसे एप्लिकेशन स्थिति के साथ सिंक्रोनाइज़ करें।
  • हमेशा पहले कंट्रोल पर फ़ोकस करना → लंबी सामग्री स्क्रीन के बाहर शुरू हो सकती है और विनाशकारी काम खतरनाक कार्रवाई पर फ़ोकस कर सकता है → सामग्री संरचना और परिणाम से प्रारंभिक फ़ोकस चुनें।
  • एक एक्सेसिबल विवरण में कई पैराग्राफ़ डालना → स्क्रीन रीडर एक असंरचित ब्लॉक की घोषणा करते हैं → केवल एक संक्षिप्त विवरण का संदर्भ लें और समृद्ध सामग्री को नेविगेट करने योग्य छोड़ दें।
  • केवल Escape पर निर्भर रहना → टच और स्विच उपयोगकर्ताओं के पास कोई स्पष्ट डिस्मिसल पाथ नहीं हो सकता है → एक दृश्यमान, नामित क्लोज़ या कैंसल कंट्रोल शामिल करें।
  • प्रत्येक बैकड्रॉप क्लिक पर बंद होना → आकस्मिक पॉइंटर इनपुट काम को छोड़ देता है → लाइट-डिस्मिस को एक विचारशील, परीक्षण योग्य उत्पाद नीति बनाएं।
  • प्लेटफ़ॉर्म या लाइब्रेरी की जांच करने से पहले एक मैनुअल फ़ोकस ट्रैप लिखना → अक्षम कंट्रोल्स, DOM परिवर्तन, पोर्टल्स, और नेस्टेड डायलॉग्स के आसपास एज केस बढ़ते हैं → नेटिव एलिमेंट या एक परिपक्व परीक्षित प्रिमिटिव को प्राथमिकता दें।
  • रेंडर के दौरान या प्रत्येक इफ़ेक्ट रन पर showModal() को कॉल करना → सर्वर रेंडरिंग विफल हो जाती है या ब्राउज़र एरर थ्रो करता है और फ़ोकस रीसेट हो जाता है → गार्डेड इफ़ेक्ट्स में अनिवार्य विधियों को कॉल करें।
  • हटाए गए ट्रिगर पर फ़ोकस रीस्टोर करना → फ़ोकस दस्तावेज़ बॉडी पर गिर जाता है और कीबोर्ड संदर्भ खो जाता है → जब वर्कफ़्लो पेज को बदलता है तो कॉलर को एक तार्किक उत्तराधिकारी की पहचान करने दें।
  • एक स्वचालित स्कैन को पूर्ण प्रमाण मानना → यह फ़ोकस ऑर्डर या वर्कफ़्लो इरादे का न्याय नहीं कर सकता → पूर्ण मैनुअल कीबोर्ड और स्क्रीन-रीडर अनुक्रम का प्रदर्शन करें।

फ़ॉलो-अप प्रश्न और उत्तर

फ़ॉलो-अप 1: यदि नेटिव डायलॉग एलिमेंट निषिद्ध है तो क्या बदलता है?

एक विज़िबल-टाइटल संदर्भ और मोडल सिमेंटिक्स के साथ एक डायलॉग-रोल कंटेनर वाले पोर्टल को रेंडर करें। प्रत्येक बैकग्राउंड एप्लिकेशन रूट को इनर्ट बनाएं, केवल विज़ुअली डिम नहीं। ओपनर को कैप्चर करें, इनिशियल फ़ोकस चुनें और सेट करें, फ़ोकस करने योग्य डिसेंडेंट्स के बदलने पर दोनों टैब दिशाओं को समाहित करें, सक्रिय डायलॉग पर Escape को संभालें, फ़ोकस रीस्टोर करें, और प्रत्येक म्यूटेशन व लिसनर को साफ़ करें। स्पष्ट करें कि प्रत्येक उत्पाद डायलॉग के लिए इस क्रॉस-ब्राउज़र व्यवहार को पुन: लागू करने की तुलना में एक मेंटेन किया गया प्रिमिटिव अधिक सुरक्षित क्यों है।

फ़ॉलो-अप 2: आप वैलिडेशन त्रुटियों वाले फ़ॉर्म को कैसे संभालते हैं?

डायलॉग को खुला रखें। फ़ोकस को पहले अमान्य फ़ील्ड या एक त्रुटि सारांश पर ले जाएं जो अमान्य फ़ील्ड से लिंक करता है, प्रत्येक संदेश को उसके फ़ील्ड के एक्सेसिबल विवरण के माध्यम से उजागर करें, और दर्ज किए गए मानों को सुरक्षित रखें। प्रत्येक फ़ील्ड त्रुटि को एक डायलॉग विवरण के रूप में घोषित न करें। एक सफल सबमिट के बाद, केवल तभी बंद करें जब एप्लिकेशन परिणाम कमिट हो जाए, फिर फ़ोकस को उस एलिमेंट पर ले जाएं जो परिणाम का प्रतिनिधित्व करता है।

फ़ॉलो-अप 3: क्या बैकड्रॉप पर क्लिक करने से डायलॉग बंद होना चाहिए?

इसे डेटा खोने के जोखिम से तय करें। एक हल्का पिकर इसकी अनुमति दे सकता है; एक लंबे फ़ॉर्म या विनाशकारी पुष्टिकरण के लिए आमतौर पर एक स्पष्ट निर्णय की आवश्यकता होनी चाहिए। यदि सक्षम है, तो केवल तभी डिस्मिस करें जब पॉइंटर अनुक्रम बैकड्रॉप क्षेत्र में शुरू और समाप्त होता है, Cancel के समान स्थिति संक्रमण का उपयोग करें, और अंदर पॉइंटर डाउन के बाद बाहर पॉइंटर अप का परीक्षण करें ताकि ड्रैग को इरादा न समझा जाए।

फ़ॉलो-अप 4: आप फ़ोकस रेस्टोरेशन को तोड़े बिना क्लोज़ को कैसे एनिमेट करते हैं?

"अनुरोधित क्लोज़" को "DOM से हटाए गए" से अलग करें। डायलॉग को क्लोज़िंग के रूप में चिह्नित करें, नई कार्रवाइयों को रोकें, एग्ज़िट ट्रांज़िशन चलाएं, फिर नेटिव क्लोज़ पाथ को कॉल करें और अनमाउंट करने से पहले स्थिति को अपडेट करें। रिड्यूस्ड-मोशन वरीयताओं का सम्मान करें और एक बाउंडेड कंप्लीशन फ़ॉलबैक प्रदान करें। फ़ोकस रेस्टोरेशन वास्तविक क्लोज़ बाउंड्री पर होता है, न कि तब जब ओपेसिटी पहली बार बदलती है।

फ़ॉलो-अप 5: क्या होगा यदि पहले डायलॉग से दूसरा डायलॉग खुलता है?

जब एक ही डायलॉग के भीतर एक बहु-चरणीय प्रवाह स्पष्ट हो तो इससे बचें। यदि आवश्यक हो, तो प्रत्येक प्रविष्टि के लिए एक ओपनर के साथ एक ऑर्डर्ड स्टैक स्टोर करें। केवल शीर्ष प्रविष्टि Escape या बैकड्रॉप पर प्रतिक्रिया देती है; निचले डायलॉग अवरुद्ध रहते हैं। चाइल्ड को बंद करने से पैरेंट के अंदर इसके ओपनर पर फ़ोकस रीस्टोर होता है, और फिर पैरेंट को बंद करने से पेज ओपनर पर फ़ोकस रीस्टोर होता है।

फ़ॉलो-अप 6: आप बॉडी स्क्रॉल और लेआउट शिफ्ट को कैसे रोकते हैं?

स्क्रॉल लॉकिंग को सिमेंटिक इनर्टनेस से अलग एक विज़ुअल और इनपुट नीति के रूप में मानें। वर्तमान स्क्रॉल स्थिति को रिकॉर्ड करें, पहला मोडल खुला होने पर एक केंद्रीकृत लॉक लागू करें, आवश्यकता पड़ने पर गायब होने वाले स्क्रॉलबार की चौड़ाई की भरपाई करें, और अंतिम मोडल बंद होने के बाद ही रिलीज़ करें। मोबाइल वर्चुअल कीबोर्ड, नेस्टेड स्क्रॉल क्षेत्र, ज़ूम, और रूट परिवर्तनों का परीक्षण करें; संदर्भ-गणना (reference-counted) स्वामित्व एक डायलॉग को दूसरे के नीचे पेज को अनलॉक करने से रोकता है।

फ़ॉलो-अप 7: आप CI में इसका परीक्षण कैसे करेंगे?

नियंत्रित ओपन और क्लोज़ ट्रांज़िशन, लेबल्स, इनिशियल-फ़ोकस शाखाओं, कैंसल हैंडलिंग, और क्लीनअप के लिए कंपोनेंट परीक्षणों का उपयोग करें। ऐसे ब्राउज़र परीक्षण जोड़ें जो वास्तविक ट्रिगर को सक्रिय करते हैं, फ़ोकस के माध्यम से आगे और पीछे जाते हैं, Escape दबाते हैं, ओपनर को हटाते हैं, और स्टैक्ड डायलॉग्स का अभ्यास करते हैं। संरचनात्मक रिग्रेशन के लिए स्वचालित एक्सेसिबिलिटी नियम चलाएं, फिर प्रतिनिधि स्क्रीन रीडर, कीबोर्ड, ज़ूम, टच, और हाई-कॉन्ट्रास्ट कॉन्फ़िगरेशन में एक मैनुअल मैट्रिक्स बनाए रखें क्योंकि CI असर्शन प्रत्येक घोषणा या वर्कफ़्लो विकल्प का न्याय नहीं कर सकते हैं।

सार्वजनिक स्रोत

संबंधित प्रश्न