Skip to content

Commit 0638b2d

Browse files
feat: Backdrop, VisuallyHidden and FocusTrap docs added
1 parent dfa8abe commit 0638b2d

11 files changed

Lines changed: 492 additions & 9 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use client';
2+
import { useFocusTrap } from '@primereact/headless/focustrap';
3+
import * as React from 'react';
4+
5+
export default function BasicDemo() {
6+
const { containerRef, firstHiddenElementRef, lastHiddenElementRef, firstHiddenProps, lastHiddenProps } = useFocusTrap();
7+
8+
return (
9+
<div className="max-w-xs mx-auto">
10+
<span ref={firstHiddenElementRef} tabIndex={0} {...firstHiddenProps} className="sr-only" />
11+
<div ref={containerRef} className="flex flex-col gap-4 p-5 rounded-lg border border-surface-200">
12+
<h5 className="text-sm font-semibold text-surface-900">Register</h5>
13+
<input type="text" placeholder="Name" className="w-full px-3 py-2 text-sm rounded-md border border-surface-200 bg-surface-0 text-surface-900 outline-none focus:ring-1 focus:ring-primary" />
14+
<input type="email" placeholder="Email" className="w-full px-3 py-2 text-sm rounded-md border border-surface-200 bg-surface-0 text-surface-900 outline-none focus:ring-1 focus:ring-primary" />
15+
<button type="submit" className="w-full px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-contrast cursor-pointer hover:bg-primary-emphasis transition">
16+
Submit
17+
</button>
18+
</div>
19+
<span ref={lastHiddenElementRef} tabIndex={0} {...lastHiddenProps} className="sr-only" />
20+
</div>
21+
);
22+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
.wrapper {
2+
display: flex;
3+
justify-content: center;
4+
}
5+
6+
.trigger {
7+
display: inline-flex;
8+
align-items: center;
9+
justify-content: center;
10+
padding: 0.5rem 1rem;
11+
border-radius: 0.5rem;
12+
border: none;
13+
background-color: var(--p-primary-color);
14+
color: var(--p-primary-contrast-color);
15+
font-weight: 500;
16+
font-size: 0.875rem;
17+
cursor: pointer;
18+
transition: background-color 200ms ease;
19+
user-select: none;
20+
}
21+
22+
.trigger:hover {
23+
background-color: var(--p-primary-hover-color);
24+
}
25+
26+
.trigger:active {
27+
background-color: var(--p-primary-active-color);
28+
}
29+
30+
.trigger:focus-visible {
31+
outline: 1px solid var(--p-primary-color);
32+
outline-offset: 2px;
33+
}
34+
35+
.backdrop {
36+
position: fixed;
37+
inset: 0;
38+
display: flex;
39+
align-items: center;
40+
justify-content: center;
41+
background-color: rgba(0, 0, 0, 0.5);
42+
z-index: 50;
43+
}
44+
45+
.dialog {
46+
background-color: light-dark(var(--p-surface-0), var(--p-surface-900));
47+
border-radius: 0.75rem;
48+
padding: 2rem;
49+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
50+
text-align: center;
51+
max-width: 24rem;
52+
}
53+
54+
.text {
55+
margin: 0 0 1rem;
56+
color: var(--p-text-color);
57+
font-size: 0.875rem;
58+
line-height: 1.5;
59+
}
60+
61+
.close {
62+
display: inline-flex;
63+
align-items: center;
64+
justify-content: center;
65+
padding: 0.5rem 1rem;
66+
border-radius: 0.5rem;
67+
border: 1px solid var(--p-content-border-color);
68+
background: transparent;
69+
color: var(--p-text-color);
70+
font-weight: 500;
71+
font-size: 0.875rem;
72+
cursor: pointer;
73+
transition: background-color 200ms ease;
74+
user-select: none;
75+
}
76+
77+
.close:hover {
78+
background-color: light-dark(var(--p-surface-50), var(--p-surface-800));
79+
}
80+
81+
.close:focus-visible {
82+
outline: 1px solid var(--p-primary-color);
83+
outline-offset: 2px;
84+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use client';
2+
import { Backdrop } from 'primereact/backdrop';
3+
import * as React from 'react';
4+
import styles from './basic-demo.module.css';
5+
6+
export default function BasicDemo() {
7+
const [visible, setVisible] = React.useState(false);
8+
9+
return (
10+
<div className={styles.wrapper}>
11+
<button className={styles.trigger} onClick={() => setVisible(true)}>
12+
Show Backdrop
13+
</button>
14+
<Backdrop
15+
visible={visible}
16+
className={styles.backdrop}
17+
motionProps={{ name: 'p-overlay-mask', appear: true }}
18+
onClick={() => setVisible(false)}
19+
>
20+
<div className={styles.dialog} onClick={(e) => e.stopPropagation()}>
21+
<p className={styles.text}>Click outside to dismiss the backdrop.</p>
22+
<button className={styles.close} onClick={() => setVisible(false)}>
23+
Close
24+
</button>
25+
</div>
26+
</Backdrop>
27+
</div>
28+
);
29+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.root {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 1rem;
5+
max-width: 20rem;
6+
margin-inline: auto;
7+
padding: 1.25rem;
8+
border-radius: 0.5rem;
9+
border: 1px solid var(--p-content-border-color);
10+
}
11+
12+
.heading {
13+
font-size: 0.875rem;
14+
font-weight: 600;
15+
color: var(--p-text-color);
16+
margin: 0;
17+
}
18+
19+
.input {
20+
width: 100%;
21+
padding: 0.5rem 0.75rem;
22+
font-size: 0.875rem;
23+
border-radius: 0.375rem;
24+
border: 1px solid var(--p-content-border-color);
25+
background-color: light-dark(var(--p-surface-0), var(--p-surface-900));
26+
color: var(--p-text-color);
27+
outline: none;
28+
transition: outline 150ms ease;
29+
box-sizing: border-box;
30+
}
31+
32+
.input:focus-visible {
33+
outline: 1px solid var(--p-primary-color);
34+
outline-offset: -1px;
35+
}
36+
37+
.button {
38+
width: 100%;
39+
padding: 0.5rem 1rem;
40+
font-size: 0.875rem;
41+
font-weight: 500;
42+
border-radius: 0.375rem;
43+
border: none;
44+
background-color: var(--p-primary-color);
45+
color: var(--p-primary-contrast-color);
46+
cursor: pointer;
47+
transition: background-color 200ms ease;
48+
user-select: none;
49+
}
50+
51+
.button:hover {
52+
background-color: var(--p-primary-hover-color);
53+
}
54+
55+
.button:active {
56+
background-color: var(--p-primary-active-color);
57+
}
58+
59+
.button:focus-visible {
60+
outline: 1px solid var(--p-primary-color);
61+
outline-offset: 2px;
62+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use client';
2+
import { FocusTrap } from 'primereact/focustrap';
3+
import styles from './basic-demo.module.css';
4+
5+
export default function BasicDemo() {
6+
return (
7+
<FocusTrap className={styles.root}>
8+
<h5 className={styles.heading}>Register</h5>
9+
<input type="text" placeholder="Name" className={styles.input} />
10+
<input type="email" placeholder="Email" className={styles.input} />
11+
<button type="submit" className={styles.button}>
12+
Submit
13+
</button>
14+
</FocusTrap>
15+
);
16+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.wrapper {
2+
display: flex;
3+
justify-content: center;
4+
gap: 0.75rem;
5+
}
6+
7+
.button {
8+
display: inline-flex;
9+
align-items: center;
10+
justify-content: center;
11+
width: 2.5rem;
12+
height: 2.5rem;
13+
border-radius: 0.5rem;
14+
border: 1px solid var(--p-content-border-color);
15+
background: transparent;
16+
color: var(--p-text-color);
17+
font-size: 1rem;
18+
cursor: pointer;
19+
transition: background-color 200ms ease;
20+
user-select: none;
21+
}
22+
23+
.button:hover {
24+
background-color: light-dark(var(--p-surface-50), var(--p-surface-800));
25+
}
26+
27+
.button:focus-visible {
28+
outline: 1px solid var(--p-primary-color);
29+
outline-offset: 2px;
30+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use client';
2+
import { VisuallyHidden } from 'primereact/visuallyhidden';
3+
import styles from './basic-demo.module.css';
4+
5+
export default function BasicDemo() {
6+
return (
7+
<div className={styles.wrapper}>
8+
<button className={styles.button}>
9+
<i className="pi pi-heart" />
10+
<VisuallyHidden>Add to favorites</VisuallyHidden>
11+
</button>
12+
13+
<button className={styles.button}>
14+
<i className="pi pi-trash" />
15+
<VisuallyHidden>Delete item</VisuallyHidden>
16+
</button>
17+
18+
<button className={styles.button}>
19+
<i className="pi pi-cog" />
20+
<VisuallyHidden>Open settings</VisuallyHidden>
21+
</button>
22+
</div>
23+
);
24+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: Backdrop
3+
description: An unstyled overlay component with built-in motion animation and conditional rendering.
4+
component: backdrop
5+
---
6+
7+
<DocPrimitivesIntro description="Build fully custom overlay backdrops with complete control over visibility and animation." />
8+
9+
<DocDemoViewer name="backdrop:basic-demo" mode="collapsible"/>
10+
11+
<DocPrimitivesLinks name="Backdrop" />
12+
13+
## Features
14+
15+
- Motion-driven visibility with `useMotion` integration for enter/leave animations
16+
- Conditional rendering via `pIf` — element mounts only when the motion state allows
17+
- `data-open` attribute emitted when `visible` is `true` for CSS-based styling
18+
- Used internally by [Drawer](/docs/primitives/drawer), Dialog, and other overlay components
19+
20+
## Usage
21+
22+
```tsx
23+
import { Backdrop } from 'primereact/backdrop';
24+
```
25+
26+
```tsx
27+
<Backdrop
28+
visible={isOpen}
29+
motionProps={{ name: 'p-overlay-mask', appear: true }}
30+
onClick={onClose}
31+
>
32+
</Backdrop>
33+
```
34+
35+
## Behavior
36+
37+
### Motion Animation
38+
39+
```tsx
40+
<Backdrop
41+
visible={isOpen}
42+
motionProps={{ name: 'fade-in', appear: true }}
43+
/>
44+
```
45+
46+
See [Motion](/docs/primitives/motion) for animation phases, CSS variables, and hide strategies.
47+
48+
### Polymorphic Rendering
49+
50+
Use `as` to change the rendered HTML element.
51+
52+
```tsx
53+
<Backdrop as="section" visible={isOpen} />
54+
```
55+
56+
### Render Function Children
57+
58+
```tsx
59+
<Backdrop visible={isOpen}>
60+
{(instance) => <div>{instance.motion.state.rendered ? 'Visible' : 'Hidden'}</div>}
61+
</Backdrop>
62+
```
63+
64+
## API
65+
66+
### Backdrop
67+
68+
<DocApiTable name="Backdrop" category="api" />
69+
70+
| Attribute | Value |
71+
| ----------- | ---------------------------------- |
72+
| `data-open` | Present when `visible` is `true` |
73+
74+
## Accessibility
75+
76+
### Screen Reader
77+
78+
Backdrop is a visual-only overlay element. It does not convey any semantic meaning to assistive technologies. Modal components that use Backdrop (such as [Drawer](/docs/primitives/drawer) and Dialog) are responsible for providing the necessary ARIA attributes on their content regions.
79+
80+
### Keyboard Support
81+
82+
Backdrop does not handle keyboard events directly. Parent overlay components implement focus trap and escape key handling.

0 commit comments

Comments
 (0)