---
title: "डायलॉग"
description: "व्यक्ति को किसी ऐसे फ़ैसले या कुछ ऐसी जानकारियों के लिए रोकता है जिनके बिना काम आगे नहीं बढ़ सकता, एक ऐसी सरफ़ेस में जो अपने पीछे की हर चीज़ को धुँधला करके तब तक रोके रखती है जब तक उसका जवाब न दे दिया जाए या उसे ख़ारिज न कर दिया जाए।"
url: "https://tanrei.chnotchy.com/hi/components/dialog/"
last_updated: 2026-10-23T21:17:12.000Z
---

# डायलॉग

> व्यक्ति को किसी ऐसे फ़ैसले या कुछ ऐसी जानकारियों के लिए रोकता है जिनके बिना काम आगे नहीं बढ़ सकता, एक ऐसी सरफ़ेस में जो अपने पीछे की हर चीज़ को धुँधला करके तब तक रोके रखती है जब तक उसका जवाब न दे दिया जाए या उसे ख़ारिज न कर दिया जाए।

## अवलोकन

> [!NOTE]
> **संशोधित स्पेक, जो अभी हर प्लैटफ़ॉर्म पर नहीं है**
>
> यह पेज डायलॉग को वैसा बताता है जैसा स्पेक में वह अभी है: हर डायलॉग कम से कम एक क्रिया देता है, क्रियाएँ tonal Button की पूरी चौड़ाई वाली एक पंक्ति हैं जिन्हें उनके काम के अनुसार जगह मिलती है, आइकन शुरू की सीध में रखी हेडलाइन के बग़ल में रहता है, और कॉम्पैक्ट विंडो पर डायलॉग नीचे रहता है। वेब कंपोनेंट इस संशोधन को इम्प्लीमेंट करता है, और इस पेज के डेमो में वही वेब कंपोनेंट है जो आज दिया जाता है; जब तक संशोधन की समीक्षा नहीं हो जाती और उसकी बेसलाइन रिकॉर्ड नहीं हो जातीं, तब तक वह ऊपर “पीछे” के रूप में ही दर्ज रहता है। SwiftUI, Compose, Flutter और React Native, जब तक वे बराबरी पर नहीं आते, पिछला संशोधन देते हैं: बीच में रखी हेडलाइन के ऊपर आइकन, अंत की ओर एक पंक्ति में दिए गए क्रम में text क्रियाएँ, वैकल्पिक क्रियाएँ, और हर विंडो में बीच में रखा डायलॉग।

### इस्तेमाल

डायलॉग कंट्रोल्ड है। आप उसे `open` सेट करके खोलते हैं और `open` को वापस false करके बंद करते हैं, किसी क्रिया के हैंडलर से या `dismiss` के जवाब में। कोई क्रिया डायलॉग को कभी अपने आप बंद नहीं करती, इसलिए आप पहले वैलिडेशन कर सकते हैं, प्रगति दिखा सकते हैं, या त्रुटि होने पर उसे खुला रख सकते हैं।

डायलॉग में एक वैकल्पिक आइकन, एक हेडलाइन, वैकल्पिक सहायक टेक्स्ट, आपका अपना वैकल्पिक कॉन्टेंट और उसकी क्रियाएँ होती हैं। डायलॉग एक संवाद है: वह हमेशा कम से कम एक जवाब सामने रखता है। क्रियाएँ Tanrei के Button हैं, और हर एक पर `confirming` (वह काम पूरा करती है: सेव करें, हटाएँ, अनुमति दें) या `dismissive` (वह पीछे हटती है: रद्द करें, अभी नहीं) का निशान होता है। डायलॉग उन्हें इन्हीं निशानों के अनुसार जगह देता है, इसलिए आप उन्हें किसी भी क्रम में दे सकते हैं, और जिस क्रिया का `variant` आपने सेट नहीं किया, उसे वह tonal बनाता है।

डायलॉग को उसके कॉन्टेंट की चौड़ाई के बजाय एक तय चौड़ाई देने के लिए `width` को `small`, `medium` या `large` पर सेट करें। डायलॉग में क्लोज़ बटन नहीं होता: बिना जवाब दिए निकलने का उसका रास्ता ‘रद्द करें’ जैसी पीछे हटने वाली क्रिया है।

जिस एलिमेंट को डायलॉग खुलने पर फ़ोकस मिलना चाहिए, उस पर प्लैटफ़ॉर्म का अपना निशान लगाएँ: वेब पर `autofocus`, SwiftUI पर `.defaultFocus` या कोई `@AccessibilityFocusState`, Compose पर `initialFocus` के रूप में दिया गया `FocusRequester`, Flutter पर `autofocus: true`, और React Native पर `initialFocusRef`। निशान न हो, तो फ़ोकस ख़ुद डायलॉग पर जाता है, इसलिए सबसे पहले उसकी हेडलाइन पढ़ी जाती है।

Web और React के उदाहरण मौजूदा स्पेक दिखाते हैं। SwiftUI, Compose, Flutter और React Native पीछे हैं: वे अभी डायलॉग का पिछला संशोधन देते हैं, जिसमें न `confirming` या `dismissive` के निशान हैं, न tonal डिफ़ॉल्ट। इसलिए उनके उदाहरण हर क्रिया को text वेरिएंट देते हैं और पुष्टि करने वाली क्रिया को आख़िर में रखते हैं, और जब तक वे बराबरी पर नहीं आते, वही संशोधन दिखाते हैं।

**Web**

```html
<tanrei-button id="discard-draft" variant="text">ड्राफ़्ट छोड़ें</tanrei-button>

<!-- closedby="none" का मतलब है dismissible को false करना। -->
<tanrei-dialog headline="ड्राफ़्ट छोड़ें?"
               supporting-text="आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।">
  <!-- dismissive शुरू में जाती है, confirming अंत में। variant के बिना दोनों tonal हैं। -->
  <!-- autofocus शुरुआती फ़ोकस का निशान है: सबसे कम विनाशकारी क्रिया। -->
  <tanrei-button slot="actions" dismissive autofocus>रद्द करें</tanrei-button>
  <tanrei-button slot="actions" confirming>छोड़ें</tanrei-button>
</tanrei-dialog>

<!-- हेडलाइन के बग़ल में एक आइकन, और एक क्रिया जिसे उसका अपना variant दिया गया है। -->
<tanrei-dialog headline="प्रोजेक्ट हटाएँ?" alert>
  <span slot="icon">delete</span>
  <tanrei-button slot="actions" dismissive variant="text">रद्द करें</tanrei-button>
  <tanrei-button slot="actions" confirming variant="filled" destructive>हटाएँ</tanrei-button>
</tanrei-dialog>

<!-- एक फ़ॉर्म: 'सहेजें' के बग़ल में 'रद्द करें', और तय चौड़ाई। डायलॉग में क्लोज़ बटन नहीं होता। -->
<tanrei-dialog headline="डिस्प्ले नाम बदलें" width="small">
  <tanrei-text-input label="डिस्प्ले नाम" autofocus></tanrei-text-input>
  <tanrei-button slot="actions" dismissive>रद्द करें</tanrei-button>
  <tanrei-button slot="actions" confirming>सहेजें</tanrei-button>
</tanrei-dialog>

<script type="module">
  import '@tanrei/web/components/dialog';
  const dialog = document.querySelector('tanrei-dialog');
  const cancel = dialog.querySelector('[dismissive]');
  const discard = dialog.querySelector('[confirming]');
  document.querySelector('#discard-draft').addEventListener('click', () => (dialog.open = true));
  // कोई क्रिया डायलॉग को कभी बंद नहीं करती: उसे आप बंद करते हैं, क्रिया के हैंडलर से।
  cancel.addEventListener('click', () => (dialog.open = false));
  discard.addEventListener('click', () => { discardDraft(); dialog.open = false; });
  // Escape और बैकड्रॉप पर दबाना cancel फ़ायर करते हैं, जैसे नेटिव <dialog> पर;
  // e.detail.reason बताता है कि कौन-सा: escape, back या scrim।
  // इसके बाद डायलॉग ख़ुद बंद हो जाता है, बशर्ते आप इवेंट को रद्द न करें।
  dialog.addEventListener('cancel', (e) => { if (unsaved()) e.preventDefault(); });
  // close हर बार बंद होने के बाद आता है।
  dialog.addEventListener('close', onDialogClosed);
</script>
```

**React**

```tsx
import { Button, Dialog } from '@tanrei/react';

// Escape और बैकड्रॉप डायलॉग को ख़ुद बंद करते हैं (onCancel, फिर onClose): onClose से open को उसके साथ मिलाकर रखें।
<Dialog
  open={open}
  headline="ड्राफ़्ट छोड़ें?"
  supportingText="आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।"
  onClose={() => setOpen(false)}
>
  <Button slot="actions" dismissive onClick={() => setOpen(false)}>रद्द करें</Button>
  <Button slot="actions" confirming onClick={discard}>छोड़ें</Button>
</Dialog>
```

**SwiftUI**

```swift
import Tanrei

// एक मॉडिफ़ायर, जैसे .alert और .sheet हैं। ख़ारिज होने पर बाइंडिंग में false लिखा जाता है।
TanreiButton("ड्राफ़्ट छोड़ें", variant: .text) { showDiscard = true }
    .tanreiDialog("ड्राफ़्ट छोड़ें?", isPresented: $showDiscard,
                  supportingText: "आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।",
                  actions: {
                      TanreiButton("रद्द करें", variant: .text) { showDiscard = false }
                      TanreiButton("छोड़ें", variant: .text) { discardDraft(); showDiscard = false }
                  })
```

**Compose**

```kotlin
import io.github.chnotchy.tanrei.components.TanreiButton
import io.github.chnotchy.tanrei.components.TanreiDialog
import io.github.chnotchy.tanrei.tokens.TanreiButtonVariant

// इसे सिर्फ़ खुला रहने पर कॉल करने की जगह visible, ताकि बाहर जाने का मोशन चल सके।
val cancel = remember { FocusRequester() }
TanreiDialog(
    visible = open,
    onDismissRequest = { open = false },
    headline = "ड्राफ़्ट छोड़ें?",
    supportingText = "आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।",
    initialFocus = cancel,
    actions = {
        TanreiButton(text = "रद्द करें", onClick = { open = false }, modifier = Modifier.focusRequester(cancel), variant = TanreiButtonVariant.Text)
        TanreiButton(text = "छोड़ें", onClick = { discardDraft(); open = false }, variant = TanreiButtonVariant.Text)
    },
)
```

**Flutter**

```dart
import 'package:tanrei/tanrei.dart';

// showTanreiDialog एक मोडल रूट पुश करता है। Navigator.pop उसे बंद करता है; ख़ारिज होने पर future null के साथ पूरा होता है।
final bool? discard = await showTanreiDialog<bool>(
  context: context,
  barrierDismissible: true, // स्पेक का dismissible: Escape, बैक और स्क्रिम
  builder: (BuildContext context) => TanreiDialog(
    headline: 'ड्राफ़्ट छोड़ें?',
    supportingText: 'आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।',
    actions: <Widget>[
      TanreiButton(
        variant: TanreiButtonVariant.text,
        autofocus: true,
        onPressed: () => Navigator.pop(context, false),
        child: const Text('रद्द करें'),
      ),
      TanreiButton(
        variant: TanreiButtonVariant.text,
        onPressed: () => Navigator.pop(context, true),
        child: const Text('छोड़ें'),
      ),
    ],
  ),
);
```

**React Native**

```tsx
import { useRef, useState } from 'react';
import type { View } from 'react-native';
import { Button, Dialog } from '@tanrei/react-native';

const cancel = useRef<View>(null);
const [open, setOpen] = useState(false);

// नाम React Native के Modal जैसे हैं: visible से कंट्रोल्ड, और onRequestClose स्पेक का dismiss है।
<Dialog
  visible={open}
  headline="ड्राफ़्ट छोड़ें?"
  supportingText="आप जो संदेश लिख रहे थे, वह इस डिवाइस से हटा दिया जाएगा।"
  onRequestClose={() => setOpen(false)}
  initialFocusRef={cancel}
  actions={
    <>
      <Button ref={cancel} variant="text" onPress={() => setOpen(false)}>रद्द करें</Button>
      <Button variant="text" onPress={discard}>छोड़ें</Button>
    </>
  }
/>
```

## स्पेक

- Category: Containment
- Level: composed
- Listing: default
- Built from: Modal layer
- Page: https://tanrei.chnotchy.com/components/dialog/
- Spec: https://github.com/chnotchy/tanrei/blob/main/specs/dialog.spec.json

### Availability

| Design system | Has it | Notes |
| --- | --- | --- |
| Tanrei (`tanrei`) | Yes | — |
| Cupertino (Apple HIG-inspired) (`cupertino`) | Yes | — |
| M3 Expressive-like (Material 3 Expressive-inspired) (`m3-expressive-like`) | Yes | — |
| M3-like (Material 3-inspired) (`m3-like`) | Yes | — |

### Platforms

- Web: the element `<tanrei-dialog>`, registered by importing `@tanrei/web` (or only its own module, `@tanrei/web/components/dialog`).
- React: `Dialog` from `@tanrei/react`.

| Platform | Name | Status |
| --- | --- | --- |
| Web | `tanrei-dialog` | lagging |
| SwiftUI | `tanreiDialog` | lagging |
| Jetpack Compose | `TanreiDialog` | lagging |
| Flutter | `TanreiDialog` | lagging |
| React Native | `Dialog` | lagging |

Names a platform gives in its own idiom:

| Spec | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
| --- | --- | --- | --- | --- | --- |
| `open` (prop) | `open` | `isPresented` | `visible` | `showTanreiDialog` | `visible` |
| `dismissible` (prop) | `closedby` | `dismissible` | `dismissible` | `barrierDismissible` | `dismissible` |
| `dismiss` (event) | `cancel` | `isPresented` | `onDismissRequest` | `showTanreiDialog` | `onRequestClose` |

Statuses: `planned` — In the inventory. Nothing shippable exists yet. `lagging` — An implementation of an earlier spec exists; it has not caught up with the current one. `alpha` — Implemented with tests. The API may still change. `beta` — Feature complete and at parity. Only fixes are expected. `stable` — Covered by semantic versioning. `deprecated` — Still shipped; scheduled for removal.

### Anatomy

- `scrim`: The modal layer's scrim over everything behind the dialog (MDL-1). It blocks presses and, when the dialog is dismissible, dismisses it when pressed.
- `container`: The raised surface that holds everything else: centred in the window, or, in a compact window, with the bottom sheet's appearance at its bottom edge (DLG-17). It is a dialog in both places: the bottom sheet's look, not its drag. Its width follows its widest part, or the size width names (DLG-27).
- `header`: The row at the top: the icon and the headline, and nothing else (DLG-26, DLG-28). By default the icon sits at the headline's start and both are aligned to the start; a system may put the icon above a centred headline instead (DLG-9).
- `icon` (optional): A glyph that marks the kind of decision (a warning, a deletion), at the headline's start.
- `headline`: The question or statement the dialog is about, aligned to the start. It is the dialog's accessible name.
- `scroll` (optional): The area between the header and the actions that holds the supporting text and the content, and scrolls them when the dialog does not fit (DLG-11). It reaches the container's inline edges whatever inline padding the container has, so the dividers cross the whole container and nothing overflows it; inside, it insets its parts by that same padding.
- `supporting-text` (optional): What will happen, or what the person needs to know to decide. It is the dialog's accessible description.
- `content` (optional): Whatever else the decision needs: a list to choose from, a field. The dialog insets it and hands it a content color; it does not lay it out.
- `divider` (optional): Hairlines between the header and the scrolling content and between the content and the actions, drawn only while the content scrolls: for as long as it does in the default system, or only while content lies beyond each line under dividerVisibility scroll.
- `actions`: The answers: one or more Tanrei Buttons, each marked confirming or dismissive, laid out as a full-width Button group (a row that the actions share equally, or a column when they do not fit). A Button whose variant the product did not set is tonal in the default system. Required: a dialog asks something, so it always offers an answer.

### Props

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `open` | `boolean` | `false` | `open` | Whether the dialog is presented. The product opens it, and closes it from an action's handler or in answer to dismiss. |
| `headline` | `string` | `""` | `headline` | The question or statement ("Discard draft?"). Required: it is the accessible name. |
| `supportingText` | `string` | `""` | `supporting-text` | What will happen, or what the person needs to know. It is the accessible description. |
| `alert` | `boolean` | `false` | `alert` | Marks a dialog that interrupts with something urgent (a destructive confirmation, a lost connection): assistive technology reads its headline and supporting text as soon as it opens, and the web exposes it as an alertdialog. |
| `dismissible` | `boolean` | `true` | — | Whether Escape, the platform's back and a press on the scrim ask to close the dialog (dismiss). Set it to false only when the person must choose one of the actions; give such a dialog a dismissive action. A dialog has no close button (DLG-28): content that needs a way out and nothing more gets a dismissive action (Cancel, or Close where there is nothing to cancel), or belongs in a side sheet or a bottom sheet. |
| `width` | `enum`: `content`, `small`, `medium`, `large` | `"content"` | `width` | What decides the container's width while the dialog is centred (DLG-7). content: as wide as its widest part, between comp.dialog.container.min-width and comp.dialog.container.max-width (DLG-7). small, medium, large: as wide as comp.dialog.width.small, comp.dialog.width.medium or comp.dialog.width.large (400, 560 and 800 in the default system) whatever it holds, for a form or content whose width should not follow its text (DLG-27). Never wider than the window less its margins; as a sheet in a compact window every value is placed as DLG-17 says. A structural choice drawn by code, not a token axis. |
| `compactPresentation` | `enum`: `sheet`, `own` | `"sheet"` | `compact-presentation` | How the dialog is presented in a compact window, one narrower than comp.dialog.compact.window-width. sheet: with the bottom sheet's appearance at the window's bottom edge (DLG-17, DLG-18), as every dialog and every popover of Tanrei is there; it stays a dialog. own: centred in every window, as DLG-7 places it, for a dialog whose look must not change with the window (a short alert that should read as one). A structural choice drawn by code, not a token axis. |
| `dividerVisibility` | `enum`: `auto`, `always`, `scroll` | `"auto"` | `divider-visibility` | When the dividers below the header and above the actions are drawn while the supporting text and the content scroll between them. always: both, for as long as that part scrolls, wherever it is scrolled to. scroll: each only while content lies beyond it — below the header while the part is not at its top, above the actions while more of it lies below. auto takes comp.dialog.divider.visibility, the design system's answer (always in the default system). Under every choice a dialog whose parts all fit draws none. |

### Events

| Event | Description |
| --- | --- |
| `dismiss` | The person asked to close the dialog without an action: Escape, the platform's back or a press on the scrim. Carries which of these it was, named escape, back or scrim (in the platform's casing). Emitted only while dismissible is true. |

### Slots

| Slot | Description |
| --- | --- |
| `default` | The custom content, below the supporting text. |
| `icon` | A glyph at the headline's start (DLG-9). |
| `actions` | The action items: Tanrei Buttons, one at least (DLG-19), each marked confirming or dismissive. The dialog places them (DLG-10) and gives those without a variant its own (DLG-20). A fixture fills it through its items. |

### Item: `action`

One answer at the foot of the dialog: a Tanrei Button, placed by the dialog as a full-width Button group places its items and given the dialog's variant unless the product set one.

It is a Button.

Names: Web `tanrei-button`, SwiftUI `TanreiButton`, Jetpack Compose `TanreiButton`, Flutter `TanreiButton`, React Native `Button`.

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `variant` | `string` | `""` | `variant` | The Button's variant (filled, tonal, elevated, outlined, text, or one a system added). Empty, the default: the dialog gives it the variant comp.dialog.actions.variant names, tonal in the default system (DLG-20). Set it to give one action another look (a filled Delete beside a text Cancel); a Delete that destroys something also sets the Button's own destructive, which the dialog leaves as set (BTN-40). |
| `disabled` | `boolean` | `false` | `disabled` | As the Button's disabled. A disabled action keeps its place and its share of the width. |
| `confirming` | `boolean` | `false` | — | The action completes the task (OK, Save, Delete, Allow). Placed at the end of a row and at the top of a column (BGR-13, BGR-14). It decides the place only, never the look (BGR-19). |
| `dismissive` | `boolean` | `false` | — | The action backs out of the task (Cancel, Not now, Keep editing). Placed at the start of a row and at the bottom of a column (BGR-13, BGR-14). It decides the place only, never the look (BGR-19). |

| Event | Description |
| --- | --- |
| `click` | The action was activated, as the Button's click. The dialog does not close by itself (DLG-6). |

| Slot | Description |
| --- | --- |
| `label` | The Button's label, as its default slot. A fixture item's content is this label. |

### States

`enabled`

### Accessibility

- Role: `dialog`
- Labeling: The headline is the accessible name and the supporting text the description. The role is dialog, or alertdialog while alert is true (platforms without that distinction read the headline and supporting text on opening). Everything outside the dialog is hidden from assistive technology while it is open. Each action is named by its own label; confirming and dismissive are not announced, and the actions are read in the order they are placed (BGR-15).
- Minimum target size: yes

| Keys | Action |
| --- | --- |
| Tab / Shift+Tab | Move focus through the dialog's focusable elements, wrapping from the last to the first and back; focus never leaves the dialog. |
| Escape | Dismisses the dialog (emits dismiss with the reason escape) while dismissible is true; with nested dialogs, only the topmost. |
| Enter or Space | Activate the focused button (an action: its click). The dialog adds no default action to Enter. |

- The dialog has no target of its own; its actions are Tanrei Buttons, which meet the minimum target themselves (BTN-5). comp.dialog.actions.gap keeps each action's whole target in a column in the default system.
- Initial focus: mark the least destructive action (Cancel) in a destructive confirmation, the first field in a form, and nothing in a dialog whose text must be read first. Without a mark, focus goes to the container (DLG-2).
- Every dialog offers an action (DLG-19). Use dismissible false sparingly: a person using a switch or a screen reader relies on Escape and back. A dialog that must not be dismissed still needs a visible way out, a dismissive action.
- A dialog has no close button (DLG-28). Its visible way out is a dismissive action, which a person meets in the reading order of the actions; Escape, back and the scrim dismiss it as well while it is dismissible.
- Placement is by task, not by code order: in a row the dismissive action is at the start and the confirming one at the end; in a column the confirming one is on top. Focus and screen readers follow the placed order, so a sighted and a screen-reader user meet the actions in the same order.
- In a compact window the dialog takes the bottom sheet's appearance (DLG-17), as every dialog and every popover of Tanrei does, and is still a modal dialog: the same role, focus, inertness and dismissal, and no drag. A person who expects a bottom sheet's swipe to close it uses Escape, back or the scrim, or a dismissive action. compactPresentation own keeps one dialog centred in every window.
- Text size: at 200% the dialog grows up to the window; its actions stack when a label no longer fits its share (DLG-10), its supporting text and content scroll (DLG-11), and on a very short window everything scrolls together (DLG-12).
- Web: a native `<dialog>` opened with `showModal()` inside the shadow root, so the rest of the page is inert and the dialog is in the top layer. `::backdrop` draws the scrim. The `autofocus` attribute on a slotted element marks initial focus. `form method="dialog"` closes it natively, and the native `close` event follows every close.
- Where a platform presents the dialog in a window of its own (Compose's `Dialog`, React Native's `Modal`), the platform's own window dim is switched off and Tanrei draws the scrim, so every platform draws the same color.

### Behaviour

Requirements in EARS form, each with its stable id.

- **DLG-1** WHEN open becomes true THE dialog SHALL present its container on its modal layer (MDL-1, MDL-2): above everything in its window, with the layer's scrim in comp.dialog.scrim.color and comp.dialog.scrim.blur over the whole window behind it, everything outside it inert and the content behind it kept from scrolling, until it closes.
- **DLG-2** WHEN the dialog opens THE dialog SHALL move focus as its modal layer does (MDL-3): to the element in it that the product marked for initial focus (the platform's own mark, named in the platform notes) or, without one, to its container, so that assistive technology reads the headline first and the next Tab reaches the first focusable element.
- **DLG-3** WHILE the dialog is open THE dialog SHALL keep focus inside it as its modal layer does (MDL-4): Tab and Shift+Tab wrap between its last and first focusable elements, and screen-reader navigation does not leave it.
- **DLG-4** WHEN the dialog closes THE dialog SHALL return focus and restore the content behind it as its modal layer does (MDL-2, MDL-5).
- **DLG-5** WHILE dismissible is true, WHEN the user presses Escape, uses the platform's back or presses the scrim, as its modal layer answers them (MDL-6), THE dialog SHALL emit dismiss once with the reason escape, back or scrim; the product closes it by setting open to false, except on the web, where the dialog closes itself unless dismiss is cancelled, as a native dialog does. WHILE dismissible is false THE dialog SHALL ignore these inputs and emit nothing.
- **DLG-6** WHEN an action is activated THE dialog SHALL NOT close by itself; the product closes it from the action's handler by setting open to false.
- **DLG-7** WHILE the dialog is not presented as a sheet (DLG-17) — in a window at least comp.dialog.compact.window-width wide, or while compactPresentation is own — THE dialog SHALL centre its container in the window's safe area, at least comp.dialog.container.margin from every edge and from the on-screen keyboard, as wide as width names (DLG-27) — WHILE width is content, as wide as its widest part (its text, its content, or its actions in one row at their own widths) between comp.dialog.container.min-width and comp.dialog.container.max-width — but never wider than the window less the margins. There THE dialog SHALL draw its container in comp.dialog.container.color with comp.dialog.container.elevation and comp.dialog.container.shape corners eased by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0).
- **DLG-8** THE dialog SHALL inset its parts by comp.dialog.container.padding on every side and stack the header (the icon and the headline, DLG-9), the supporting text and the content comp.dialog.container.gap apart, leaving out a part that is empty, with the actions comp.dialog.actions.margin-block-start below the last of them. It SHALL draw the headline in comp.dialog.headline.typescale and comp.dialog.headline.color, wrapping onto more lines rather than truncating, and the supporting text in comp.dialog.supporting-text.typescale and comp.dialog.supporting-text.color, and SHALL hand the content comp.dialog.content.color as the platform's inherited foreground (the web's inherited color, SwiftUI's foreground style, Compose's content color, Flutter's default text and icon style, React Native's Tanrei text context); plain text given as content, where the platform must style it, SHALL take sys.typescale.body. THE dialog SHALL set the headline's letter-spacing by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them.
- **DLG-9** WHILE the icon slot is filled THE dialog SHALL draw the icon at comp.dialog.icon.size in comp.dialog.icon.color, with the family and fill of an unselected icon, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, and place it as comp.dialog.icon.placement says: WHILE it is inline, at the start of the header, comp.dialog.header.gap before the headline and centred on the headline's first line, so that a headline that wraps keeps the icon beside its first line; WHILE it is above, above the headline, comp.dialog.container.gap apart, with the icon and the headline centred. The supporting text and the content SHALL be aligned to the start in either placement, and WHILE the icon slot is empty the headline SHALL be aligned to the start whatever the placement.
- **DLG-10** THE dialog SHALL lay out its actions as a standard Button group lays out its items (BGR-12 to BGR-19), comp.dialog.actions.gap apart, in the order the group gives them — dismissive at the start and confirming at the end of a row, confirming on top and dismissive at the bottom of a column — with focus and reading order following that order (BGR-15). WHILE comp.dialog.actions.arrangement is fill it SHALL make them a full-width group across the container's inner width, the actions sharing a row equally (BGR-17) or each as wide as the column; WHILE it is end it SHALL keep them at their own widths, the row aligned to the end, and a column as wide as its widest action and aligned to the end. It SHALL place them in a row WHILE every action's label fits its share on one line (fill) or the row at its own widths fits the inner width (end), and otherwise in a column, re-deciding when the dialog's width or the text size changes.
- **DLG-11** WHEN the dialog's parts do not fit in the height its placement leaves THE dialog SHALL keep the header and the actions in place and scroll the supporting text and the content between them, and SHALL draw a divider of comp.dialog.divider.width in comp.dialog.divider.color across the container below the header and another above the actions: WHILE its divider visibility (DLG-24) is always, both for as long as that part scrolls, wherever it is scrolled to, at its top included; WHILE it is scroll, the one below the header only WHILE the scrolled part is not at its top and the one above the actions only WHILE more of it lies below. WHILE everything fits THE dialog SHALL draw no divider.
- **DLG-12** WHEN the header and the actions alone leave no room for the scrolled part (large text on a short window) THE dialog SHALL scroll all of its parts together instead, so that nothing is cut off or unreachable.
- **DLG-13** WHEN the dialog opens centred in the window (DLG-7) THE dialog SHALL fade its scrim in with its container, as its modal layer says (MDL-7), and make its container appear as every modal surface appears: from sys.motion.appear.opacity, sys.motion.appear.scale, sys.motion.appear.distance and sys.motion.appear.blur to whole, grown about its centre and travelling up into place, over comp.dialog.motion.enter-duration with comp.dialog.motion.enter-easing; WHEN it closes there it SHALL take the container back the same way to where it started while fading the scrim out, over comp.dialog.motion.exit-duration with comp.dialog.motion.exit-easing. A motion turned round SHALL go on from the opacity and the size it has reached. WHERE sys.behavior.appearance is unfold the scale SHALL apply on both axes, from the centre: a centred container has no anchored edge. WHERE motion is reduced it SHALL only fade the container in and out, over sys.motion.role.reduced, with no scale, distance or blur, or appear and disappear at once on a platform whose reduced-motion setting removes every animation (Android's). WHEN it is mounted with open true THE dialog SHALL appear without its motion while the document has not yet been first painted, and with it when it is mounted after that. Focus SHALL move (DLG-2, DLG-4) when the dialog opens or closes, not when the motion ends.
- **DLG-14** THE dialog SHALL expose its container as its modal layer's modal dialog (MDL-10) — an alert dialog WHILE alert is true — named by headline and described by supportingText; WHEN alert is true and the dialog opens it SHALL have assistive technology read the headline and the supporting text at once; WHILE headline is empty it SHALL still open, and in debug builds SHALL report that it has no accessible name.
- **DLG-15** WHEN a dialog opens while another is open THE dialog SHALL stack above it as modal layers stack (MDL-8): with its own scrim, the first one inert as well, focus returned on closing to the element inside the first dialog that had it, and Escape dismissing only the topmost dialog.
- **DLG-16** WHEN the layout direction is right-to-left THE dialog SHALL mirror its layout — the icon at the right of the headline, the headline and the supporting text aligned to the right, and its actions placed as a Button group places them right to left (BGR-8: dismissive at the right, confirming at the left of a row; a column's order unchanged) — and SHALL NOT mirror its content itself: the content follows the layout direction.
- **DLG-17** WHILE the window is narrower than comp.dialog.compact.window-width (a compact window) and compactPresentation is sheet THE dialog SHALL present its container with the bottom sheet's appearance (BSH-7): at the window's bottom edge, as wide as the window but no wider than comp.bottom-sheet.container.max-width and centred in it, whatever width names, filled with comp.bottom-sheet.container.color, raised by comp.bottom-sheet.container.elevation, its top corners rounded by comp.bottom-sheet.container.shape eased by sys.shape.corner-smoothing and its bottom corners square, its color reaching under the bottom system inset and its parts above it, sitting on the on-screen keyboard while it is shown, and never taller than the window below its top system inset less comp.bottom-sheet.container.margin-block-start. Its parts SHALL keep their own tokens and layout (DLG-8 to DLG-12, DLG-20), inside comp.dialog.container.padding. It SHALL stay a dialog there — DLG-1 to DLG-6, DLG-8 to DLG-12 and DLG-14 to DLG-16 hold unchanged, its scrim the dialog's own — and SHALL draw no drag handle, follow no drag and close on no swipe, because it has one height and its exits are its actions, Escape, back and the scrim. WHILE compactPresentation is own THE dialog SHALL be centred in every window as DLG-7 says. WHEN the window's width crosses comp.dialog.compact.window-width, or compactPresentation changes, while the dialog is open THE dialog SHALL take the other presentation at once, without motion, keeping focus where it is. WHERE comp.dialog.compact.window-width is 0 no window is compact. WHEN compactPresentation names a value the dialog does not define THE dialog SHALL treat it as sheet and in debug builds report the unknown value.
- **DLG-18** WHEN the dialog opens as a sheet in a compact window (DLG-17) THE dialog SHALL fade its scrim in (MDL-7) while sliding its container up from below the window's bottom edge into its place, as a modal bottom sheet opens (BSH-1), over comp.bottom-sheet.motion.enter-duration with comp.bottom-sheet.motion.enter-easing; WHEN it closes there it SHALL fade the scrim out while sliding the container down out of view, over comp.bottom-sheet.motion.exit-duration with comp.bottom-sheet.motion.exit-easing. WHERE motion is reduced it SHALL fade in and out in place without sliding, or appear and disappear at once on a platform whose reduced-motion setting removes every animation (Android's). Focus SHALL move as DLG-13 says.
- **DLG-19** IF the dialog opens with no action THE dialog SHALL still open and lay out its other parts, and in debug builds SHALL report as an error that a dialog must offer at least one action; a platform whose API can require an action (a required, non-empty list or builder of actions) SHALL require it, and one that can count its actions only when it opens SHALL count them then. It SHALL report likewise a dialog whose actions are all disabled while dismissible is false, which leaves the person no way out.
- **DLG-20** WHILE an action's variant is empty THE dialog SHALL give that Button the variant comp.dialog.actions.variant names, through the channel a Button reads from the component that places it, so that the Button renders from that variant's tokens and states as it would with the variant set; WHILE an action's variant is set THE dialog SHALL leave it as set. THE dialog SHALL NOT change an action's size or tokens, and SHALL NOT change its look or emphasis for its confirming or dismissive (BGR-19).
- **DLG-21** THE dialog SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the dialog is shown THE dialog SHALL draw itself for the new direction at once, without a motion of its own, keeping its open state and its focus.
- **DLG-22** WHERE the layout direction is right-to-left THE dialog SHALL draw the glyph of its icon slot mirrored left to right exactly when the system's icon set marks that glyph's name as mirrored or the product forces mirroring for that use, and unmirrored when the product forbids it: the icon helper mirrors the glyph inside its own box, about the box's vertical centre line, changing neither its place, size, color and fill nor the order DLG-16 gives. THE dialog SHALL NOT mirror a glyph itself, and SHALL NOT mirror content the product gives as an image or a view of its own rather than by a glyph's name.
- **DLG-23** THE dialog SHALL lay out its headline and its supporting text as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE dialog SHALL still place each and align its lines by the layout direction, not by the text's own.
- **DLG-24** THE dialog SHALL draw its dividers (DLG-11) as its dividerVisibility names: WHILE dividerVisibility is auto, as comp.dialog.divider.visibility names, which follows sys.behavior.divider-visibility unless a design system sets the dialog apart; WHILE dividerVisibility is always or scroll, as that value names, whatever the tokens say. WHEN dividerVisibility, or the token it follows, changes THE dialog SHALL draw the other form at once, moving no part and keeping the scroll position and focus; WHEN dividerVisibility names a value the dialog does not define THE dialog SHALL treat it as auto and in debug builds report the unknown value. A platform that cannot draw a choice SHALL fall back to the first value, always, and state that in its README.
- **DLG-26** THE dialog SHALL draw its header as one row that holds the icon and the headline as DLG-9 places them, across the container's inner width, and nothing at its end; WHILE headline is empty and the icon slot is empty THE dialog SHALL draw no header, leaving it out as DLG-8 leaves out an empty part.
- **DLG-27** WHILE the dialog is centred (DLG-7) and width is small, medium or large THE dialog SHALL make its container as wide as comp.dialog.width.small, comp.dialog.width.medium or comp.dialog.width.large, whatever its parts would ask and not held between comp.dialog.container.min-width and comp.dialog.container.max-width, but never wider than the window's safe area less comp.dialog.container.margin on each side; its headline and supporting text SHALL wrap to that width, its content SHALL take it, and its actions SHALL be placed in a row or a column as DLG-10 decides at that width. WHILE width is content THE dialog SHALL be as wide as DLG-7 says. WHILE it is a sheet THE dialog SHALL place its container as DLG-17 says, whatever width names, because a narrow window leaves no room for a choice of width. WHEN width changes while the dialog is open THE dialog SHALL take the new width at once, without a motion of its own, keeping its scroll position and focus; WHEN width names a value the dialog does not define THE dialog SHALL treat it as content and in debug builds report the unknown value.
- **DLG-28** THE dialog SHALL draw no close button in its header: a dialog asks for a decision, and its way out without one is its dismissive action and, WHILE dismissible is true, Escape, the platform's back and the scrim (DLG-5). THE dialog SHALL have no prop that draws one; WHERE a platform can be given a property the dialog does not define and the product gives one that asks for a close button (the web's closable and close-label attributes), THE dialog SHALL draw nothing for it and in debug builds SHALL report that a dialog has no close button.
- **DLG-29** WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE dialog SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on its dialog (DLG-14) — an id reference by the elements it names in the host's tree or a tree around it, a description after its own. WHILE headline is not empty it is the dialog's name, over a name given so; WHILE headline is empty, a name given so is the dialog's name and SHALL NOT be reported as having none in debug builds. WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE dialog SHALL take it off that element.

### Tokens

As written in the token documents (DTCG): an alias in braces names the token it takes its value from, which each design system resolves. On the web each token is a CSS custom property: `--tanrei` and the name after `tanrei`, joined by hyphens (`tanrei.comp.dialog.…` → `--tanrei-comp-dialog-…`).

#### `tanrei.comp.dialog`

| Token | Type | Value |
| --- | --- | --- |
| `comp.dialog.scrim.color` | `color` | `{tanrei.comp.modal-layer.scrim.color}` |
| `comp.dialog.scrim.blur` | `dimension` | `{tanrei.comp.modal-layer.scrim.blur}` |
| `comp.dialog.container.color` | `color` | `{tanrei.sys.color.surface-bright}` |
| `comp.dialog.container.elevation` | `shadow` | `{tanrei.sys.elevation.level3}` |
| `comp.dialog.container.shape` | `dimension` | `{tanrei.sys.shape.corner.large}` |
| `comp.dialog.container.padding` | `dimension` | `{tanrei.sys.space.space300}` |
| `comp.dialog.container.gap` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.dialog.container.min-width` | `dimension` | `280px` |
| `comp.dialog.container.max-width` | `dimension` | `560px` |
| `comp.dialog.container.margin` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.dialog.compact.window-width` | `dimension` | `600px` |
| `comp.dialog.header.gap` | `dimension` | `{tanrei.sys.space.space150}` |
| `comp.dialog.width.small` | `dimension` | `400px` |
| `comp.dialog.width.medium` | `dimension` | `560px` |
| `comp.dialog.width.large` | `dimension` | `800px` |
| `comp.dialog.icon.color` | `color` | `{tanrei.sys.color.secondary}` |
| `comp.dialog.icon.size` | `dimension` | `{tanrei.sys.icon.medium}` |
| `comp.dialog.icon.placement` | `number` | `0` |
| `comp.dialog.headline.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.dialog.headline.typescale` | `typography` | `{tanrei.sys.typescale.heading-5}` |
| `comp.dialog.supporting-text.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.dialog.supporting-text.typescale` | `typography` | `{tanrei.sys.typescale.body}` |
| `comp.dialog.content.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.dialog.divider.color` | `color` | `{tanrei.sys.color.outline-variant}` |
| `comp.dialog.divider.width` | `dimension` | `{tanrei.sys.border.hairline}` |
| `comp.dialog.divider.visibility` | `number` | `{tanrei.sys.behavior.divider-visibility}` |
| `comp.dialog.actions.gap` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.dialog.actions.margin-block-start` | `dimension` | `{tanrei.sys.space.space300}` |
| `comp.dialog.actions.arrangement` | `number` | `0` |
| `comp.dialog.actions.variant` | `number` | `1` |
| `comp.dialog.motion.enter-duration` | `duration` | `{tanrei.comp.modal-layer.motion.enter-duration}` |
| `comp.dialog.motion.enter-easing` | `cubicBezier` | `{tanrei.comp.modal-layer.motion.enter-easing}` |
| `comp.dialog.motion.exit-duration` | `duration` | `{tanrei.comp.modal-layer.motion.exit-duration}` |
| `comp.dialog.motion.exit-easing` | `cubicBezier` | `{tanrei.comp.modal-layer.motion.exit-easing}` |

## दिशानिर्देश

### कब इस्तेमाल करें

डायलॉग तब इस्तेमाल करें जब काम किसी जवाब के बिना आगे नहीं बढ़ सकता: किसी ऐसी चीज़ की पुष्टि जिसे पहले जैसा नहीं किया जा सकता, कोई अनुमति माँगना, या पेज छोड़े बिना दो-तीन जानकारियाँ लेना। यह व्यक्ति को रोकता है, इसलिए इसे तभी इस्तेमाल करें जब उसे रोकना सचमुच ज़रूरी हो।

जिस चीज़ को पहले जैसा किया जा सकता है, उसके लिए “क्या आप निश्चित हैं?” पूछने की जगह स्नैकबार से बताएँ कि अभी क्या हुआ, चाहें तो “पहले जैसा करें” के साथ। ऐसे छोटे चुनाव के लिए मेन्यू इस्तेमाल करें जो स्क्रीन को नहीं रोकता। लंबे फ़ॉर्म और जटिल काम उनके अपने पेज पर रखें।

### भाग

| भाग | किससे सेट होता है | टिप्पणी |
| --- | --- | --- |
| आइकन | आइकन स्लॉट | वैकल्पिक। एक ग्लिफ़ जो बताता है कि फ़ैसला किस तरह का है, जैसे `delete`। यह हेडलाइन की पहली पंक्ति के शुरू में, उससे 12 पहले रहता है, और हेडलाइन के अगली पंक्ति में जाने पर भी उसी पंक्ति के बग़ल में रहता है। |
| हेडलाइन | `headline` | ज़रूरी। सवाल या कथन, जैसे “ड्राफ़्ट छोड़ें?”। हमेशा शुरू की सीध में। यही डायलॉग का एक्सेसिबल नाम है। |
| सहायक टेक्स्ट | `supportingText` | क्या होगा, या फ़ैसला करने के लिए व्यक्ति को क्या जानना ज़रूरी है। हमेशा शुरू की सीध में। यही डायलॉग का विवरण है। |
| कॉन्टेंट | डिफ़ॉल्ट स्लॉट | फ़ैसले के लिए और जो कुछ चाहिए: चुनने के लिए एक लिस्ट, एक फ़ील्ड। डायलॉग उसे इनसेट देता है और कॉन्टेंट का रंग देता है; उसका लेआउट नहीं करता। |
| क्रियाएँ | actions स्लॉट | ज़रूरी: Tanrei का कम से कम एक Button, हर एक पर `confirming` या `dismissive` का निशान। डायलॉग उन्हें पूरी चौड़ाई वाले एक बटन ग्रुप के रूप में रखता है और जिन पर वेरिएंट नहीं है, उन्हें tonal बनाता है। |

जब ये भाग विंडो में नहीं समाते, तो हेडर और क्रियाएँ अपनी जगह रहती हैं, और सहायक टेक्स्ट और कॉन्टेंट उनके बीच स्क्रॉल होते हैं। जब तक वे स्क्रॉल होते हैं, ऊपरी सिरे पर रहते हुए भी, बारीक रेखा वाला एक डिवाइडर हेडर को उनसे अलग करता है और दूसरा क्रियाओं को। `dividerVisibility` को `scroll` पर सेट करें (वेब पर `divider-visibility`) ताकि हर डिवाइडर तभी दिखे जब उसके पार कुछ स्क्रॉल होकर नज़र से बाहर हो; `cupertino` और `m3-like` हर डायलॉग के लिए यही चुनते हैं। जब बड़ा टेक्स्ट इसके लिए भी जगह नहीं छोड़ता, तो पूरा डायलॉग बिना डिवाइडर के स्क्रॉल होता है।

वेब पर, स्क्रॉल होने वाला भाग `::part(scroll)` है। आप `::part(container)` को दाएँ-बाएँ जो भी पैडिंग दें, यह भाग कंटेनर के किनारों तक पहुँचता है और अंदर वही पैडिंग रखता है, इसलिए इसके डिवाइडर पूरे डायलॉग के आर-पार जाते हैं और कुछ भी बाहर नहीं निकलता। अगर आपका कॉन्टेंट `position: sticky` से कोई पंक्ति नीचे टिकाए रखता है, तो स्क्रॉल होने वाले भाग को बताएँ कि वह पंक्ति कितनी ऊँची है, ताकि फ़ोकस मिलने पर स्क्रॉल होकर सामने आया फ़ील्ड उसके नीचे न छिपे:

```css
tanrei-dialog::part(scroll) { scroll-padding-block-end: 56px; }
```

सहायक टेक्स्ट के बिना हेडलाइन की अनुमति है: हेडलाइन में एक सवाल और उसके जवाब, यह एक संवाद है। डायलॉग जो नहीं हो सकता, वह है ऐसा कथन जिसका जवाब देने को कुछ न हो।

### क्रियाएँ

क्रियाएँ कंटेनर की भीतरी चौड़ाई को बराबर बाँटती हैं, और उनके बीच 16 का गैप रहता है।

- **काम के अनुसार जगह।** पंक्ति में पीछे हटने वाली क्रिया शुरू में और पुष्टि करने वाली क्रिया अंत में रहती है। कॉलम में पुष्टि करने वाली क्रिया सबसे ऊपर और पीछे हटने वाली सबसे नीचे रहती है। जिस क्रिया पर दोनों में से कोई निशान नहीं है, वह इन दोनों के बीच अपनी दी हुई जगह पर रहती है। फ़ोकस और स्क्रीन रीडर इसी रखे गए क्रम में चलते हैं, इसलिए आपको Button का क्रम कभी हाथ से नहीं लगाना पड़ता।
- **जगह के अनुसार पंक्ति या कॉलम।** जब तक हर लेबल अपने हिस्से में एक पंक्ति में समाता है, क्रियाएँ एक पंक्ति में रहती हैं। जब कोई लेबल अगली पंक्ति में जाने लगे, तो वे एक कॉलम में एक के ऊपर एक आ जाती हैं, हर एक डायलॉग जितनी चौड़ी। डायलॉग की चौड़ाई या टेक्स्ट का साइज़ बदलने पर वह यह फ़ैसला फिर से करता है।
- **डिफ़ॉल्ट रूप से tonal।** जिस क्रिया का `variant` आपने सेट नहीं किया, वह tonal बनती है। निशान सिर्फ़ जगह तय करते हैं, रूप कभी नहीं।
- **कोई और रूप।** किसी क्रिया को दूसरा रूप देने के लिए उस एक Button का `variant` सेट करें, जैसे filled “हटाएँ” के बग़ल में text “रद्द करें”। जो क्रिया कुछ हटाती या छोड़ देती है, जैसे यही “हटाएँ”, उस पर `destructive` सेट करें: वह अपना वेरिएंट रखती है और एरर का रंग लेती है। डायलॉग आपका सेट किया हुआ वेरिएंट कभी नहीं बदलता, और `destructive` भी नहीं। जो प्रॉडक्ट हर डायलॉग के लिए दूसरा रूप चाहता है, वह उसे हर Button पर नहीं, अपनी लेयर में एक बार सेट करता है (`actions.variant`, और अंत की सीध में रखी, अपनी-अपनी चौड़ाई वाली क्रियाओं के लिए `actions.arrangement`)।
- **कम से कम एक।** बिना किसी क्रिया वाला डायलॉग फिर भी खुलता है, और डीबग बिल्ड इसे त्रुटि के रूप में रिपोर्ट करते हैं। जहाँ प्लैटफ़ॉर्म का API क्रियाओं को ज़रूरी बना सकता है, वहाँ स्पेक कहता है कि वह ऐसा करता है: SwiftUI का `actions:` बिल्डर, Compose का `actions` पैरामीटर, Flutter की `actions` लिस्ट और React Native की `actions` प्रॉपर्टी। इन चारों में आज सिर्फ़ SwiftUI वाला ज़रूरी है; बाक़ी, जब तक वे बराबरी पर नहीं आते, बिना क्रियाओं वाला डायलॉग अब भी ले लेते हैं। डीबग बिल्ड उस डायलॉग की भी रिपोर्ट करते हैं जिसकी सारी क्रियाएँ अक्षम हों और `dismissible` false हो, क्योंकि तब बाहर निकलने का कोई रास्ता नहीं बचता।

### क्लोज़ बटन नहीं

डायलॉग अपने हेडर में कोई क्लोज़ बटन नहीं बनाता। वह एक फ़ैसला माँगता है, और फ़ैसला किए बिना निकलने का उसका रास्ता उसकी पीछे हटने वाली क्रिया है, और जब तक `dismissible` true है, Escape, प्लैटफ़ॉर्म का बैक और स्क्रिम पर दबाना।

- **फ़ॉर्म या चुनाव।** पुष्टि वाली क्रिया के बग़ल में ‘रद्द करें’ जैसी पीछे हटने वाली क्रिया रखें, जैसा ऊपर है।
- **पढ़ने के लिए कुछ।** डायलॉग को ‘बंद करें’ लेबल वाली एक क्रिया दें (रद्द करने को कुछ हो, तो ‘रद्द करें’), और उस पर `dismissive` का निशान लगाएँ। अगर कॉन्टेंट को जवाब नहीं, सिर्फ़ निकलने का रास्ता चाहिए, तो उसे डायलॉग के बजाय साइड शीट में दिखाएँ, जिसमें क्लोज़ बटन होता है, या बॉटम शीट में, जिसे व्यक्ति स्वाइप करके हटा सकता है।
- **लंबा डायलॉग।** जब उसका कॉन्टेंट स्क्रॉल होता है, क्रियाएँ नीचे अपनी जगह पर टिकी रहती हैं, इसलिए निकलने का रास्ता दिखता रहता है।
- **वेब पर।** डायलॉग को `closable` या `close-label` दिया जाए, तो वह उसके लिए कुछ नहीं बनाता, और डीबग बिल्ड बताते हैं कि डायलॉग में क्लोज़ बटन नहीं होता।

### चौड़ाई

डिफ़ॉल्ट रूप से (`width` content), डायलॉग अपने सबसे चौड़े भाग जितना चौड़ा होता है, 280 और 560 के बीच। तब उसकी चौड़ाई उसके टेक्स्ट के हिसाब से चलती है, जो पुष्टि के लिए ठीक है। इसके बजाय तय चौड़ाई देने के लिए `width` सेट करें, ताकि फ़ॉर्म के फ़ील्ड और संदेश बदलने पर भी उसकी चौड़ाई न बदले:

| `width` | चौड़ाई | किसके लिए |
| --- | --- | --- |
| `content` | सबसे चौड़ा भाग, 280 से 560 | पुष्टि या छोटा सवाल (डिफ़ॉल्ट) |
| `small` | 400 | एक-दो फ़ील्ड |
| `medium` | 560 | फ़ॉर्म, विकल्पों की सूची |
| `large` | 800 | जगह माँगने वाला कॉन्टेंट, जैसे टेबल या प्रीव्यू |

तय चौड़ाई कभी भी विंडो की चौड़ाई में से दोनों ओर 16 घटाने से ज़्यादा नहीं होती, इसलिए 640 की विंडो में large डायलॉग 608 चौड़ा होता है। कॉम्पैक्ट विंडो (600 से सँकरी) पर हर चौड़ाई डिफ़ॉल्ट की तरह रखी जाती है: नीचे एक शीट के रूप में, विंडो जितनी चौड़ी, अधिकतम 640 तक। डायलॉग खुला हो और `width` बदले, तो नई चौड़ाई तुरंत दिखती है। कोई प्रोडक्ट अपनी लेयर में सभी डायलॉग की तीनों चौड़ाइयाँ बदल सकता है (`width.small`, `width.medium`, `width.large`)।

### कॉम्पैक्ट विंडो पर

जब विंडो 600 से सँकरी होती है, तो डायलॉग बीच में रहने की जगह बॉटम शीट का रूप-रंग ले लेता है। कॉम्पैक्ट विंडो में हर डायलॉग और हर पॉपओवर के लिए यह Tanrei का नियम है। डायलॉग विंडो के निचले किनारे पर (या ऑन-स्क्रीन कीबोर्ड के ऊपर) रहता है, विंडो जितना चौड़ा, अधिकतम `comp.bottom-sheet.container.max-width` (640) तक, बॉटम शीट के रंग और एलिवेशन में, ऊपर बॉटम शीट के गोल कोनों और नीचे सीधे कोनों के साथ। उसका रंग नीचे के सिस्टम इनसेट के नीचे तक जाता है, और उसके भाग डायलॉग की अपनी पैडिंग और टेक्स्ट स्टाइल बनाए रखते हैं। सिर्फ़ चौड़ाई गिनी जाती है, इसलिए लैंडस्केप में रखा फ़ोन कॉम्पैक्ट नहीं है और उसका डायलॉग बीच में रहता है।

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

जो सिस्टम डायलॉग को हर जगह बीच में रखता है, वह कॉम्पैक्ट चौड़ाई को 0 पर सेट करता है। `m3-like` और `cupertino` प्रीसेट ऐसा ही करते हैं, क्योंकि दोनों के मूल सिस्टम अपने डायलॉग बीच में रखते हैं। वे अपने मूल सिस्टम की text क्रियाएँ भी बनाए रखते हैं। किसी एक डायलॉग को हर विंडो में बीच में रखने के लिए उसका `compactPresentation` `own` करें (वेब पर `compact-presentation="own"`)।

### खुलना, फ़ोकस और बंद होना

डायलॉग एक मोडल ओवरले है। यह फ़ोकस को भीतर ले जाता है, उसे भीतर रखता है, और बंद होने पर लौटा देता है।

- **खुलना।** जब `open` true होता है, तो डायलॉग अपनी विंडो की हर चीज़ के ऊपर, बीच में (या कॉम्पैक्ट विंडो में सबसे नीचे), एक ऐसे स्क्रिम पर पेश किया जाता है जो पूरी विंडो को धुँधला करता है। उसके बाहर की हर चीज़ निष्क्रिय हो जाती है: उस पर न फ़ोकस जा सकता है, न उसे दबाया जा सकता है, और सहायक तकनीक उस तक नहीं पहुँच सकती। उसके पीछे का कॉन्टेंट स्क्रॉल होना बंद कर देता है।
- **फ़ोकस का भीतर जाना।** फ़ोकस उस एलिमेंट पर जाता है जिस पर आपने निशान लगाया है, या ख़ुद डायलॉग पर, ताकि सहायक तकनीक पहले हेडलाइन पढ़े और अगली Tab फ़ोकस पा सकने वाले पहले एलिमेंट पर पहुँचे। फ़ोकस डायलॉग के खुलते ही जाता है, उसका मोशन ख़त्म होने पर नहीं।
- **फ़ोकस का भीतर रहना।** फ़ोकस पा सकने वाले आख़िरी एलिमेंट से Tab पहले पर जाती है, और पहले से Shift+Tab आख़िरी पर। स्क्रीन रीडर का नेविगेशन डायलॉग से बाहर नहीं जाता।
- **ख़ारिज करना।** जब तक `dismissible` true है, Escape, प्लैटफ़ॉर्म का बैक (Android का बैक बटन या जेस्चर, iOS का एक्सेसिबिलिटी एस्केप जेस्चर) और स्क्रिम पर दबाना एक बार `dismiss` एमिट करते हैं, और डायलॉग को आप बंद करते हैं। वेब पर, अगर आप `cancel` को रद्द न करें, तो डायलॉग ख़ुद बंद हो जाता है, जैसे नेटिव `<dialog>` होता है। जब `dismissible` false है, तब ये कुछ नहीं करते, और डायलॉग को सिर्फ़ कोई क्रिया बंद करती है। कॉम्पैक्ट विंडो में नीचे रखा डायलॉग स्वाइप से बंद नहीं होता। `dismiss` अपना कारण साथ लाता है: `escape`, `back` या `scrim`।
- **फ़ोकस की वापसी।** बंद होने पर फ़ोकस उस एलिमेंट पर लौटता है जिस पर वह डायलॉग खुलते समय था। उसके पीछे का कॉन्टेंट वैसा ही बहाल हो जाता है जैसा वह था।
- **एक के ऊपर एक।** किसी डायलॉग से खोला गया डायलॉग अपने स्क्रिम के साथ उसके ऊपर आता है और पहले वाले को भी निष्क्रिय कर देता है। Escape सिर्फ़ सबसे ऊपर वाले को ख़ारिज करती है, और उसके बंद होने पर फ़ोकस पहले डायलॉग के भीतर के उस एलिमेंट पर लौटता है जिस पर वह था।
- **पढ़कर सुनाया जाना।** डायलॉग को डायलॉग के रूप में पढ़कर सुनाया जाता है, जिसका नाम उसकी हेडलाइन और विवरण उसका सहायक टेक्स्ट है। `alert` के साथ यह एक अलर्ट डायलॉग है, और सहायक तकनीक उसके खुलते ही हेडलाइन और सहायक टेक्स्ट पढ़ती है।
- **मोशन।** स्क्रिम फ़ेड होकर आता है। बीच में रखा कंटेनर अपने साइज़ से थोड़े छोटे से बढ़ते हुए फ़ेड होकर आता है। कॉम्पैक्ट विंडो में कंटेनर बॉटम शीट के मोशन से, बिना बढ़े, निचले किनारे के नीचे से ऊपर आता है, और बंद होते समय वापस नीचे जाता है। जहाँ मोशन कम किया गया है, वहाँ यह बिना बढ़े या खिसके फ़ेड होता है; Android पर, जिसकी सेटिंग हर ऐनिमेशन हटा देती है, यह तुरंत दिखता है।

हर प्लैटफ़ॉर्म इसे कैसे पेश करता है: वेब पर `showModal()` से खोला गया नेटिव `<dialog>`, iOS के SwiftUI पर पारदर्शी बैकग्राउंड वाला `.fullScreenCover` (macOS पर, जहाँ फ़ुल-स्क्रीन कवर नहीं है, उस व्यू पर एक ओवरले जिससे मॉडिफ़ायर जुड़ा है), Compose पर एक `Dialog` विंडो, Flutter पर एक मोडल रूट, और React Native पर एक पारदर्शी `Modal`। हर एक अपना धुँधलापन और अपना ट्रांज़िशन बंद कर देता है, इसलिए हर प्लैटफ़ॉर्म टोकन से एक ही स्क्रिम और एक ही मोशन बनाता है।

जो स्नैकबार अभी दिखाया नहीं गया है, वह Tanrei का डायलॉग खुला रहने तक इंतज़ार करता है, और जो पहले से दिख रहा है, वह अपना टाइमआउट रोक देता है। डायलॉग के भीतर का टूलटिप उसके ऊपर बनता है।

### करें

- हेडलाइन को सीधे सवाल या कथन के रूप में लिखें: “ड्राफ़्ट छोड़ें?”, “प्रोजेक्ट हटाएँ?”। “क्या आप निश्चित हैं?” से बचें।
- क्रियाओं का नाम उस काम पर रखें जो वे करती हैं: “छोड़ें”, “हटाएँ”, “साइन आउट करें”। “हाँ” और “नहीं” से बचें।
- हर क्रिया पर `confirming` या `dismissive` का निशान लगाएँ, और उन्हें जगह डायलॉग को देने दें।
- हर डायलॉग को एक जवाब दें। जो डायलॉग सिर्फ़ सूचना देता है, वह असल में एक स्नैकबार है या पेज की एक पंक्ति।
- पढ़ने के लिए कुछ दिखाने वाले डायलॉग को ‘बंद करें’ या ‘रद्द करें’ लेबल वाली एक क्रिया दें, या वह कॉन्टेंट साइड शीट में दिखाएँ।
- विनाशकारी पुष्टि में शुरुआती फ़ोकस का निशान “रद्द करें” पर लगाएँ। फ़ॉर्म में पहले फ़ील्ड पर लगाएँ। जिस डायलॉग का टेक्स्ट पहले पढ़ा जाना ज़रूरी है, उसमें किसी पर निशान न लगाएँ।
- `alert` सिर्फ़ तुरंत ध्यान माँगने वाली रुकावटों के लिए सेट करें: कोई विनाशकारी पुष्टि, टूटा हुआ कनेक्शन।

### न करें

- ऐसा डायलॉग न खोलें जो व्यक्ति ने नहीं माँगा, जब तक कि काम सचमुच आगे न बढ़ सकता हो।
- हेडर या कॉन्टेंट में अपना कोई क्लोज़ बटन न जोड़ें: डायलॉग में क्लोज़ बटन नहीं होता, और उससे निकलने का रास्ता पीछे हटने वाली क्रिया है।
- `dismissible` को false न करें, जब तक कि व्यक्ति के लिए क्रियाओं में से कोई एक चुनना अनिवार्य न हो। स्विच और स्क्रीन रीडर इस्तेमाल करने वाले लोग Escape और बैक पर निर्भर रहते हैं। जिस डायलॉग को ख़ारिज नहीं किया जा सकता, उसे भी बाहर निकलने का एक दिखने वाला रास्ता चाहिए, जैसे “रद्द करें”।
- डायलॉग में कुछ ही जानकारियों से ज़्यादा न रखें। लंबा फ़ॉर्म एक पेज पर रखें।
- पुष्टि करने वाली क्रिया को आख़िर में रखने के लिए क्रियाओं का क्रम हाथ से न लगाएँ, और tonal पाने के लिए हर Button पर वेरिएंट सेट न करें: ये दोनों काम डायलॉग करता है।
- बटनों की स्टाइल उनके `variant` से आगे न बदलें, और डायलॉग के फ़्रेम में कंट्रोल न जोड़ें।
- कॉम्पैक्ट विंडो में नीचे रखे डायलॉग को बॉटम शीट न समझें। जब व्यक्ति को उसे स्वाइप करके हटा पाना चाहिए, तब बॉटम शीट इस्तेमाल करें।

## सुलभता

### कंपोनेंट क्या सँभालता है

- डायलॉग सहायक तकनीक को मोडल डायलॉग के रूप में मिलता है, या `alert` के true रहते अलर्ट डायलॉग के रूप में, जिसका नाम उसकी हेडलाइन और विवरण उसका सहायक टेक्स्ट है। `alert` के साथ हेडलाइन और सहायक टेक्स्ट उसके खुलते ही पढ़े जाते हैं।
- उसके खुला रहते उसके बाहर की हर चीज़ निष्क्रिय रहती है और सहायक तकनीक से छिपी रहती है।
- खुलने पर फ़ोकस उस एलिमेंट पर जाता है जिस पर आपने निशान लगाया है, या ख़ुद डायलॉग पर। Tab और Shift+Tab उसके भीतर ही घूमती रहती हैं। बंद होने पर फ़ोकस उस एलिमेंट पर लौटता है जिस पर वह खुलते समय था।
- जब तक `dismissible` true है, Escape, प्लैटफ़ॉर्म का बैक और स्क्रिम पर दबाना `dismiss` एमिट करते हैं। एक के ऊपर एक खुले डायलॉग में सिर्फ़ सबसे ऊपर वाला ख़ारिज होता है।
- Enter और Space फ़ोकस वाले बटन को सक्रिय करती हैं। डायलॉग Enter पर कोई डिफ़ॉल्ट क्रिया नहीं जोड़ता।
- क्रियाएँ Tanrei के Button हैं, जो न्यूनतम टार्गेट ख़ुद पूरा करते हैं। एक के ऊपर एक रखी क्रियाओं के बीच का 16 हर टार्गेट को पूरा रखता है।
- फ़ोकस और स्क्रीन रीडर को क्रियाएँ उसी रखे गए क्रम में मिलती हैं जिसमें देख सकने वाला व्यक्ति उन्हें देखता है।
- कॉम्पैक्ट विंडो में सबसे नीचे भी डायलॉग का रोल, फ़ोकस, बाक़ी सब का निष्क्रिय होना और ख़ारिज होना वही रहता है। जो व्यक्ति बॉटम शीट वाले स्वाइप की उम्मीद करता है, वह इसे Escape, बैक, स्क्रिम या पीछे हटने वाली किसी क्रिया से बंद करता है।
- 200% टेक्स्ट साइज़ पर डायलॉग विंडो तक बढ़ता है, जब कोई लेबल अपने हिस्से में नहीं समाता तो उसकी क्रियाएँ एक के ऊपर एक आ जाती हैं, सहायक टेक्स्ट और कॉन्टेंट स्क्रॉल होते हैं, और बहुत कम ऊँचाई वाली विंडो पर सब कुछ एक साथ स्क्रॉल होता है, इसलिए न कुछ कटता है, न पहुँच से बाहर रहता है।
- बिना हेडलाइन या बिना क्रिया वाला डायलॉग फिर भी खुलता है, और डीबग बिल्ड नाम के न होने या जवाब के न होने की रिपोर्ट करते हैं। वे उस डायलॉग की भी रिपोर्ट करते हैं जिसकी सारी क्रियाएँ अक्षम हों और `dismissible` false हो।

प्लैटफ़ॉर्म की ज्ञात कमियाँ:

- SwiftUI, Compose, Flutter और React Native: `dividerVisibility` इन प्लैटफ़ॉर्म के बराबरी पर आने का इंतज़ार कर रहा है। इनके डिवाइडर `scroll` की तरह तभी दिखते हैं जब उनके पार कुछ स्क्रॉल होकर नज़र से बाहर हो।
- SwiftUI, Compose, Flutter और React Native: `width` और `dismiss` के साथ आने वाला कारण उन प्लैटफ़ॉर्म के बराबर आने का इंतज़ार कर रहे हैं।
- Web: Firefox बंद होते डायलॉग को फ़ेड होने के दौरान टॉप लेयर में नहीं रख पाता, इसलिए वहाँ डायलॉग बंद होते ही, बाहर जाने वाले फ़ेड के बिना, तुरंत ग़ायब हो जाता है।
- Web: ऑन-स्क्रीन कीबोर्ड से हटकर रहना अभी किसी ऐसे डिवाइस पर जाँचा नहीं गया है जिसमें वह हो।
- SwiftUI में न डायलॉग का रोल है, न अलर्ट डायलॉग का। कंटेनर पर मोडल ट्रेट होता है, उसका नाम हेडलाइन है और सहायक टेक्स्ट उसके हिंट के रूप में उसका विवरण है, और हेडलाइन पर हेडिंग ट्रेट होता है। `alert` के साथ VoiceOver डायलॉग के खुलते ही हेडलाइन और सहायक टेक्स्ट पढ़ता है।
- macOS के SwiftUI में फ़ुल-स्क्रीन कवर नहीं है: डायलॉग सिर्फ़ उस व्यू को ढकता है जिससे मॉडिफ़ायर जुड़ा है, इसलिए उसे विंडो के रूट से जोड़ें। डायलॉग के खुला रहते वह व्यू अक्षम रहता है, और उसके कंट्रोल स्क्रिम के नीचे अपना अक्षम स्टेट बनाते हैं।
- SwiftUI कीबोर्ड फ़ोकस को ख़ुद डायलॉग पर नहीं ले जा सकता। निशान न हो, तो VoiceOver हेडलाइन से शुरू करता है। बंद होने पर iOS VoiceOver का फ़ोकस पेश करने वाले एलिमेंट पर लौटा देता है, पर कीबोर्ड फ़ोकस न iOS पर लौटाया जाता है, न macOS पर।
- Compose में अलर्ट डायलॉग का रोल नहीं है। विंडो हेडलाइन के नाम वाला एक डायलॉग है, और `alert` वाला डायलॉग खुलते समय अपनी हेडलाइन और सहायक टेक्स्ट को Android के एक ऐसे API से पढ़कर सुनाता है जिसे Android 16 डेप्रिकेट करता है।
- Compose: असली डायलॉग विंडो, Tab का भीतर घूमते रहना, फ़ोकस का खोलने वाले एलिमेंट पर लौटना, बैक जेस्चर और TalkBack सिर्फ़ Robolectric पर टेस्ट किए गए हैं, अभी किसी डिवाइस पर नहीं।
- Flutter: जब हेडलाइन और क्रियाएँ भी जगह नहीं छोड़तीं और पूरा डायलॉग एक साथ स्क्रॉल होता है, तो यह बदलाव एक लेआउट के बाद तय होता है और एक फ़्रेम देर से दिखता है। Flutter में विवरण की कोई प्रॉपर्टी नहीं है, इसलिए सहायक टेक्स्ट कंटेनर का हिंट है। जब तक आप `barrierLabel` नहीं देते, स्क्रिम का कोई एक्सेसिबल लेबल नहीं होता।
- React Native यह नहीं बता सकता कि फ़ोकस किस एलिमेंट पर था, इसलिए बंद होने पर फ़ोकस उस एलिमेंट पर नहीं लौटता जिसने डायलॉग खोला था: फ़ोकस वहाँ जाता है जहाँ iOS और Android किसी बंद हुई विंडो के बाद उसे रखते हैं। `initialFocusRef` के बिना सिर्फ़ स्क्रीन रीडर का फ़ोकस जाता है (हेडलाइन पर); हार्डवेयर कीबोर्ड का फ़ोकस वहीं रह जाता है जहाँ प्लैटफ़ॉर्म उसे नई विंडो में रखता है।
- React Native: Tab डायलॉग के भीतर घूमती रहती है या नहीं, यह प्लैटफ़ॉर्म तय करता है। यह बात, स्क्रीन रीडर का फ़ोकस, बैक, iOS का एस्केप जेस्चर और डायलॉग के भीतर डायलॉग अभी किसी डिवाइस पर जाँचे नहीं गए हैं।
- React Native: डायलॉग सेफ़ एरिया के भीतर तभी रहता है जब आप विंडो के इनसेट `TanreiProvider` को देते हैं।

### आपको क्या करना है

- हर डायलॉग को एक हेडलाइन दें। वही डायलॉग का नाम है।
- हर डायलॉग को कम से कम एक क्रिया दें, और हर एक पर `confirming` या `dismissive` का निशान लगाएँ। जो प्लैटफ़ॉर्म अभी पिछला संशोधन देते हैं, उन पर पुष्टि करने वाली क्रिया को ख़ुद आख़िर में रखें।
- डायलॉग को ख़ुद बंद करें: हर क्रिया के हैंडलर से, और `dismiss` के जवाब में (प्लैटफ़ॉर्म के अनुसार `onRequestClose`, `onDismissRequest`, बाइंडिंग या रूट)।
- जहाँ मदद मिले, वहाँ शुरुआती फ़ोकस का निशान लगाएँ: विनाशकारी पुष्टि में “रद्द करें” पर, फ़ॉर्म में पहले फ़ील्ड पर।
- हर डायलॉग को बाहर निकलने का एक दिखने वाला रास्ता दें, यानी “रद्द करें” जैसी पीछे हटने वाली कोई क्रिया, तब भी जब `dismissible` false हो।
- React Native पर `initialFocusRef` दें। डायलॉग बंद होने के बाद, अगर प्लैटफ़ॉर्म ऐसा नहीं करता, तो फ़ोकस को ख़ुद उसे खोलने वाले एलिमेंट पर लौटाएँ।
- macOS के SwiftUI पर `.tanreiDialog` को विंडो के रूट व्यू से जोड़ें, ताकि स्क्रिम पूरी विंडो को ढके।
- वेब पर, अगर आपका कॉन्टेंट नीचे कोई पंक्ति टिकाए रखता है, तो `::part(scroll)` पर `scroll-padding-block-end` को उस पंक्ति की ऊँचाई पर सेट करें, ताकि फ़ोकस वाला एलिमेंट कभी उसके नीचे न छिपे।
