kopia lustrzana https://github.com/shoelace-style/shoelace
264 wiersze
8.3 KiB
Markdown
264 wiersze
8.3 KiB
Markdown
<!-- cspell:dictionaries lorem-ipsum -->
|
|
|
|
# Dialog
|
|
|
|
[component-header:sl-dialog]
|
|
|
|
```html preview
|
|
<sl-dialog label="Dialog" class="dialog-overview">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
<sl-button slot="footer" variant="primary">Close</sl-button>
|
|
</sl-dialog>
|
|
|
|
<sl-button>Open Dialog</sl-button>
|
|
|
|
<script>
|
|
const dialog = document.querySelector('.dialog-overview');
|
|
const openButton = dialog.nextElementSibling;
|
|
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
|
|
|
openButton.addEventListener('click', () => dialog.show());
|
|
closeButton.addEventListener('click', () => dialog.hide());
|
|
</script>
|
|
```
|
|
|
|
```jsx react
|
|
import { useState } from 'react';
|
|
import { SlButton, SlDialog } from '@shoelace-style/shoelace/dist/react';
|
|
|
|
const App = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<SlDialog label="Dialog" open={open} onSlAfterHide={() => setOpen(false)}>
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
|
|
Close
|
|
</SlButton>
|
|
</SlDialog>
|
|
|
|
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
|
|
</>
|
|
);
|
|
};
|
|
```
|
|
|
|
## UX Tips
|
|
|
|
- Use a dialog when you immediately require the user's attention, e.g. confirming a destructive action.
|
|
- Always provide an obvious way for the user to dismiss the dialog.
|
|
- Don't nest dialogs. It almost always leads to a poor experience for the user.
|
|
|
|
## Examples
|
|
|
|
### Custom Width
|
|
|
|
Use the `--width` custom property to set the dialog's width.
|
|
|
|
```html preview
|
|
<sl-dialog label="Dialog" class="dialog-width" style="--width: 50vw;">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
<sl-button slot="footer" variant="primary">Close</sl-button>
|
|
</sl-dialog>
|
|
|
|
<sl-button>Open Dialog</sl-button>
|
|
|
|
<script>
|
|
const dialog = document.querySelector('.dialog-width');
|
|
const openButton = dialog.nextElementSibling;
|
|
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
|
|
|
openButton.addEventListener('click', () => dialog.show());
|
|
closeButton.addEventListener('click', () => dialog.hide());
|
|
</script>
|
|
```
|
|
|
|
```jsx react
|
|
import { useState } from 'react';
|
|
import { SlButton, SlDialog } from '@shoelace-style/shoelace/dist/react';
|
|
|
|
const App = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<SlDialog label="Dialog" open={open} style={{ '--width': '50vw' }} onSlAfterHide={() => setOpen(false)}>
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
|
|
Close
|
|
</SlButton>
|
|
</SlDialog>
|
|
|
|
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
|
|
</>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Scrolling
|
|
|
|
By design, a dialog's height will never exceed that of the viewport. As such, dialogs will not scroll with the page ensuring the header and footer are always accessible to the user.
|
|
|
|
```html preview
|
|
<sl-dialog label="Dialog" class="dialog-scrolling">
|
|
<div style="height: 150vh; border: dashed 2px var(--sl-color-neutral-200); padding: 0 1rem;">
|
|
<p>Scroll down and give it a try! 👇</p>
|
|
</div>
|
|
<sl-button slot="footer" variant="primary">Close</sl-button>
|
|
</sl-dialog>
|
|
|
|
<sl-button>Open Dialog</sl-button>
|
|
|
|
<script>
|
|
const dialog = document.querySelector('.dialog-scrolling');
|
|
const openButton = dialog.nextElementSibling;
|
|
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
|
|
|
openButton.addEventListener('click', () => dialog.show());
|
|
closeButton.addEventListener('click', () => dialog.hide());
|
|
</script>
|
|
```
|
|
|
|
```jsx react
|
|
import { useState } from 'react';
|
|
import { SlButton, SlDialog } from '@shoelace-style/shoelace/dist/react';
|
|
|
|
const App = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<SlDialog label="Dialog" open={open} onSlAfterHide={() => setOpen(false)}>
|
|
<div
|
|
style={{
|
|
height: '150vh',
|
|
border: 'dashed 2px var(--sl-color-neutral-200)',
|
|
padding: '0 1rem'
|
|
}}
|
|
>
|
|
<p>Scroll down and give it a try! 👇</p>
|
|
</div>
|
|
|
|
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
|
|
Close
|
|
</SlButton>
|
|
</SlDialog>
|
|
|
|
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
|
|
</>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Preventing the Dialog from Closing
|
|
|
|
By default, dialogs will close when the user clicks the close button, clicks the overlay, or presses the <kbd>Escape</kbd> key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.
|
|
|
|
To keep the dialog open in such cases, you can cancel the `sl-request-close` event. When canceled, the dialog will remain open and pulse briefly to draw the user's attention to it.
|
|
|
|
You can use `event.detail.source` to determine what triggered the request to close. This example prevents the dialog from closing when the overlay is clicked, but allows the close button or <kbd>Escape</kbd> to dismiss it.
|
|
|
|
```html preview
|
|
<sl-dialog label="Dialog" class="dialog-deny-close">
|
|
This dialog will not close when you click on the overlay.
|
|
<sl-button slot="footer" variant="primary">Close</sl-button>
|
|
</sl-dialog>
|
|
|
|
<sl-button>Open Dialog</sl-button>
|
|
|
|
<script>
|
|
const dialog = document.querySelector('.dialog-deny-close');
|
|
const openButton = dialog.nextElementSibling;
|
|
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
|
|
|
openButton.addEventListener('click', () => dialog.show());
|
|
closeButton.addEventListener('click', () => dialog.hide());
|
|
|
|
// Prevent the dialog from closing when the user clicks on the overlay
|
|
dialog.addEventListener('sl-request-close', event => {
|
|
if (event.detail.source === 'overlay') {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
</script>
|
|
```
|
|
|
|
```jsx react
|
|
import { useState } from 'react';
|
|
import { SlButton, SlDialog } from '@shoelace-style/shoelace/dist/react';
|
|
|
|
const App = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
// Prevent the dialog from closing when the user clicks on the overlay
|
|
function handleRequestClose(event) {
|
|
if (event.detail.source === 'overlay') {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<SlDialog label="Dialog" open={open} onSlRequestClose={handleRequestClose} onSlAfterHide={() => setOpen(false)}>
|
|
This dialog will not close when you click on the overlay.
|
|
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
|
|
Close
|
|
</SlButton>
|
|
</SlDialog>
|
|
|
|
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
|
|
</>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Customizing Initial Focus
|
|
|
|
By default, the dialog's panel will gain focus when opened. This allows a subsequent tab press to focus on the first tabbable element in the dialog. If you want a different element to have focus, add the `autofocus` attribute to it as shown below.
|
|
|
|
```html preview
|
|
<sl-dialog label="Dialog" class="dialog-focus">
|
|
<sl-input autofocus placeholder="I will have focus when the dialog is opened"></sl-input>
|
|
<sl-button slot="footer" variant="primary">Close</sl-button>
|
|
</sl-dialog>
|
|
|
|
<sl-button>Open Dialog</sl-button>
|
|
|
|
<script>
|
|
const dialog = document.querySelector('.dialog-focus');
|
|
const input = dialog.querySelector('sl-input');
|
|
const openButton = dialog.nextElementSibling;
|
|
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
|
|
|
|
openButton.addEventListener('click', () => dialog.show());
|
|
closeButton.addEventListener('click', () => dialog.hide());
|
|
</script>
|
|
```
|
|
|
|
```jsx react
|
|
import { useState } from 'react';
|
|
import { SlButton, SlDialog, SlInput } from '@shoelace-style/shoelace/dist/react';
|
|
|
|
const App = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<SlDialog label="Dialog" open={open} onSlAfterHide={() => setOpen(false)}>
|
|
<SlInput autofocus placeholder="I will have focus when the dialog is opened" />
|
|
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
|
|
Close
|
|
</SlButton>
|
|
</SlDialog>
|
|
|
|
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
|
|
</>
|
|
);
|
|
};
|
|
```
|
|
|
|
?> You can further customize initial focus behavior by canceling the `sl-initial-focus` event and setting focus yourself inside the event handler.
|
|
|
|
[component-metadata:sl-dialog]
|