Skip to content

Commit 224b2f0

Browse files
feat: deprecate classes, add data attributes
1 parent d461ad6 commit 224b2f0

File tree

9 files changed

+139
-183
lines changed

9 files changed

+139
-183
lines changed

.changeset/mighty-snails-exist.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
feat: deprecate `modal-showing` and `modal-closing` classes in favor of `data-open`, `data-closing`, and `data-closed` data attributes.
6+
7+
> These classes will still work at the moment, but will be removed in a near future release.

apps/website/src/routes/docs/headless/modal/examples/bottom-sheet.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PropsOf, component$, useSignal, useStyles$ } from '@builder.io/qwik';
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
22
import { Label, Modal, ModalDescription, ModalTitle } from '@qwik-ui/headless';
33
import styles from '../snippets/animation.css?inline';
44

@@ -12,7 +12,7 @@ export default component$(() => {
1212
<button class="modal-trigger" onClick$={() => (isOpen.value = true)}>
1313
Open Modal
1414
</button>
15-
<Modal class="modal sheet bottom-sheet" bind:show={isOpen}>
15+
<Modal class="modal bottom-sheet" bind:show={isOpen}>
1616
<ModalTitle>Edit Profile</ModalTitle>
1717
<ModalDescription>
1818
You can update your profile here. Hit the save button when finished.
@@ -34,14 +34,3 @@ export default component$(() => {
3434
</>
3535
);
3636
});
37-
38-
export function CloseIcon(props: PropsOf<'svg'>, key: string) {
39-
return (
40-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props} key={key}>
41-
<path
42-
fill="currentColor"
43-
d="m12 13.4l2.9 2.9q.275.275.7.275t.7-.275q.275-.275.275-.7t-.275-.7L13.4 12l2.9-2.9q.275-.275.275-.7t-.275-.7q-.275-.275-.7-.275t-.7.275L12 10.6L9.1 7.7q-.275-.275-.7-.275t-.7.275q-.275.275-.275.7t.275.7l2.9 2.9l-2.9 2.9q-.275.275-.275.7t.275.7q.275.275.7.275t.7-.275l2.9-2.9Zm0 8.6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22Zm0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20Zm0-8Z"
44-
></path>
45-
</svg>
46-
);
47-
}

apps/website/src/routes/docs/headless/modal/examples/sheet.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PropsOf, component$, useSignal, useStyles$ } from '@builder.io/qwik';
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
22
import { Label, Modal, ModalDescription, ModalTitle } from '@qwik-ui/headless';
33
import styles from '../snippets/animation.css?inline';
44

@@ -34,14 +34,3 @@ export default component$(() => {
3434
</>
3535
);
3636
});
37-
38-
export function CloseIcon(props: PropsOf<'svg'>, key: string) {
39-
return (
40-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props} key={key}>
41-
<path
42-
fill="currentColor"
43-
d="m12 13.4l2.9 2.9q.275.275.7.275t.7-.275q.275-.275.275-.7t-.275-.7L13.4 12l2.9-2.9q.275-.275.275-.7t-.275-.7q-.275-.275-.7-.275t-.7.275L12 10.6L9.1 7.7q-.275-.275-.7-.275t-.7.275q-.275.275-.275.7t.275.7l2.9 2.9l-2.9 2.9q-.275.275-.275.7t.275.7q.275.275.7.275t.7-.275l2.9-2.9Zm0 8.6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22Zm0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20Zm0-8Z"
44-
></path>
45-
</svg>
46-
);
47-
}
Lines changed: 25 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,34 @@
1-
import { PropsOf, component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import { Modal, ModalContent, ModalFooter, ModalHeader } from '@qwik-ui/headless';
3-
// import styles from './animation.css?inline';
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
2+
import { Modal, ModalTitle, ModalDescription, Label } from '@qwik-ui/headless';
3+
import styles from '../snippets/animation.css?inline';
44

55
export default component$(() => {
6-
const showSig = useSignal(false);
7-
useStyles$(`
8-
.modal-transition::backdrop {
9-
background: rgba(0,0,0,0.5);
10-
}
11-
12-
.modal-transition, .modal-transition::backdrop {
13-
opacity: 0;
14-
transition: opacity 300ms ease;
15-
}
16-
17-
.modal-transition, .modal-transition::backdrop {
18-
opacity: 1;
19-
}
20-
21-
.modal-transition.modal-closing, .modal-transition.modal-closing::backdrop {
22-
opacity: 0;
23-
}
24-
`);
6+
useStyles$(styles);
7+
const isOpen = useSignal(false);
258

269
return (
27-
<>
28-
<button
29-
onClick$={() => {
30-
showSig.value = true;
31-
}}
32-
class="rounded-base border px-3 py-2 hover:bg-accent/80"
33-
>
10+
<div class="modal-container">
11+
<button class="modal-trigger" onClick$={() => (isOpen.value = true)}>
3412
Open Modal
3513
</button>
36-
<Modal
37-
bind:show={showSig}
38-
class="modal-transition max-w-[25rem] rounded-base bg-background p-[28px] text-foreground shadow-md"
39-
>
40-
<ModalHeader>
41-
<h2 class="text-lg font-bold">Edit Profile</h2>
42-
</ModalHeader>
43-
<ModalContent class="mb-2 py-4">
44-
<p class="mb-4 leading-5">
45-
You can update your profile here. Hit the save button when finished.
46-
</p>
47-
<div class="mb-1 flex items-baseline justify-between">
48-
<label for="name">Name</label>
49-
<input
50-
class="mt-2 rounded-base bg-background px-4 py-[10px] text-foreground"
51-
id="name"
52-
type="text"
53-
placeholder="John Doe"
54-
/>
55-
</div>
56-
<div class="flex items-baseline justify-between">
57-
<label for="email">Email</label>
58-
<input
59-
class="mt-2 rounded-base bg-background px-4 py-3 text-foreground"
60-
id="email"
61-
type="text"
62-
placeholder="[email protected]"
63-
/>
64-
</div>
65-
</ModalContent>
66-
<ModalFooter class="flex justify-end gap-4">
67-
<button
68-
class="rounded-base border border-none bg-muted px-4 py-[10px] text-muted-foreground outline-none ring-offset-background transition-colors hover:bg-accent/90 hover:text-accent-foreground focus:ring focus:ring-ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
69-
onClick$={() => (showSig.value = false)}
70-
>
71-
Cancel
72-
</button>
73-
<button
74-
class="rounded-base border border-none bg-primary px-4 py-[10px] text-primary-foreground outline-none ring-offset-background transition-colors hover:bg-primary/90 focus:ring focus:ring-ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
75-
onClick$={() => (showSig.value = false)}
76-
>
77-
Save Changes
78-
</button>
79-
</ModalFooter>
80-
<button
81-
onClick$={() => (showSig.value = false)}
82-
class="absolute right-6 top-[26px]"
83-
>
84-
<CloseIcon class="h-8 w-8" />
85-
</button>
14+
<Modal class="modal modal-transition" bind:show={isOpen}>
15+
<ModalTitle>Edit Profile</ModalTitle>
16+
<ModalDescription>
17+
You can update your profile here. Hit the save button when finished.
18+
</ModalDescription>
19+
<Label>
20+
Name
21+
<input type="text" placeholder="John Doe" />
22+
</Label>
23+
<Label>
24+
Email
25+
<input type="text" placeholder="[email protected]" />
26+
</Label>
27+
<footer>
28+
<button onClick$={() => (isOpen.value = false)}>Cancel</button>
29+
<button onClick$={() => (isOpen.value = false)}>Save Changes</button>
30+
</footer>
8631
</Modal>
87-
</>
32+
</div>
8833
);
8934
});
90-
91-
export function CloseIcon(props: PropsOf<'svg'>, key: string) {
92-
return (
93-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props} key={key}>
94-
<path
95-
fill="currentColor"
96-
d="m12 13.4l2.9 2.9q.275.275.7.275t.7-.275q.275-.275.275-.7t-.275-.7L13.4 12l2.9-2.9q.275-.275.275-.7t-.275-.7q-.275-.275-.7-.275t-.7.275L12 10.6L9.1 7.7q-.275-.275-.7-.275t-.7.275q-.275.275-.275.7t.275.7l2.9 2.9l-2.9 2.9q-.275.275-.275.7t.275.7q.275.275.7.275t.7-.275l2.9-2.9Zm0 8.6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22Zm0-2q3.35 0 5.675-2.325T20 12q0-3.35-2.325-5.675T12 4Q8.65 4 6.325 6.325T4 12q0 3.35 2.325 5.675T12 20Zm0-8Z"
97-
></path>
98-
</svg>
99-
);
100-
}

apps/website/src/routes/docs/headless/modal/index.mdx

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,12 @@ Modals are used when an important choice needs to be made in the application. Th
4949
description: 'The root component that contains the dialog element.',
5050
},
5151
{
52-
name: 'ModalHeader',
53-
description: 'A semantic header element that titles the modal.',
52+
name: 'ModalTitle',
53+
description: 'An accessible name for the modal.',
5454
},
5555
{
56-
name: 'ModalContent',
57-
description: `The main content of the modal.`,
58-
},
59-
{
60-
name: 'ModalFooter',
61-
description: `A semantic footer element used to contain menu action buttons.`,
56+
name: 'ModalDescription',
57+
description: `An optional accessible description for the modal.`,
6258
},
6359
]}
6460
/>
@@ -171,21 +167,19 @@ Qwik UI automatically detects any `animation` or `transition` declarations under
171167

172168
<Showcase name="transition" />
173169

174-
To add an transition, use the `modal-showing` and `modal-closing` css classes. Above is a snippet where we transition both the modal and backdrop's opacity.
170+
To add an transition, use the `data-open`, `data-closing` and `data-closed` data attributes. Above is a snippet where we transition both the modal and backdrop's opacity.
175171

176172
### Adding an animation
177173

178174
<Showcase name="animatable" />
179175

180-
To add an animation, it's the same as with transitions, using the `modal-showing` and `modal-closing` css classes. Below is a snippet of the animation example above.
181-
182-
<CodeSnippet name="animation.css" />
176+
To add an animation, it's the same as with transitions, using the `data-open` and `data-closing` data attributes. Below is a snippet of the animation example above.
183177

184178
### Backdrop animations
185179

186180
Backdrop animations have also made significant progress in the last year, with support provided in over half of the major browsers, and close to 70% of users.
187181

188-
To add a backdrop animation, make sure to use the `::backdrop` pseudo selector to the end of the `modal-closing` or `modal-opening` classes.
182+
To add a backdrop animation, make sure to use the `::backdrop` pseudo selector to the end of the `data-closing` or `data-open` classes.
189183

190184
> Firefox currently does not support backdrop animations. The fallback for browsers that do not support animated backdrops is the same as a non-animated backdrop.
191185
@@ -203,10 +197,20 @@ Sheets are a type of modal/overlay used to provide temporary access to important
203197

204198
Bottom sheets are more prevalent in mobile applications, usually to simplify UI. That said, feel free to use them wherever fits best!
205199

200+
### Animations / Transitions CSS
201+
202+
<CodeSnippet name="animation.css" />
203+
206204
## Open on page load
207205

208206
There might come a time where a modal is needed open as soon as the page loads. Unfortunately, to create modals a client-side API is currently needed regardless of implementation.
209207

208+
## Example CSS
209+
210+
The example for the CSS used in all of the examples above can be found below.
211+
212+
<CodeSnippet name="modal.css" />
213+
210214
### SSR dilemma
211215

212216
Qwik is the first framework with an [SSR portal implementation](https://qwik.builder.io/docs/cookbook/portal/#solution). SSR Portal capabilities are unique to Qwik City, because the alternative frameworks require a client-side API for portal functionality, such as `document.appendChild`.
@@ -279,14 +283,19 @@ The current solution across framework ecosystems, is to open the Modal eagerly o
279283
description: 'An event hook that gets notified whenever the modal shows up.',
280284
},
281285
{
282-
name: '.modal-showing',
283-
type: 'CSS',
284-
description: 'A CSS class used for entry animations.',
286+
name: 'data-open',
287+
type: 'attribute',
288+
description: 'A data attribute used for styling open modals and entry animations.',
289+
},
290+
{
291+
name: 'data-closing',
292+
type: 'attribute',
293+
description: 'A data attribute used for exit animations.',
285294
},
286295
{
287-
name: '.modal-closing',
288-
type: 'CSS',
289-
description: 'A CSS class used for exit animations.',
296+
name: 'data-closed',
297+
type: 'attribute',
298+
description: 'A data attribute used for closed modals.',
290299
},
291300
]}
292301
/>

0 commit comments

Comments
 (0)