huntabyte / vaul-svelte

An unstyled drawer component for Svelte.
https://vaul-svelte.com
MIT License
437 stars 18 forks source link

Styling with plain CSS? #54

Closed khromov closed 7 months ago

khromov commented 7 months ago

Change Type

Addition

Proposed Changes

👋 What is the best way to style this without Tailwind? I've ported the demo to normal CSS, is there a way to avoid the :global selector?

I tried prefixing with .wrapper :global(.drawer-overlay) to scope it down but the overlay renders outside the component tree you place it in, so it does not work as it's no longer a descendent of my wrapper.

<script>
    import { Drawer } from 'vaul-svelte';
</script>

<div data-vaul-drawer-wrapper class="wrapper">
    <Drawer.Root shouldScaleBackground>
        <Drawer.Trigger>Open Drawer</Drawer.Trigger>
        <Drawer.Portal>
            <Drawer.Overlay class="drawer-overlay" />
            <Drawer.Content class="drawer-content">
                <div class="content-wrapper">
                    <div class="drag-handle" />
                    <div class="mx-auto max-w-md">
                        <Drawer.Title class="drawer-title">Unstyled drawer for Svelte.</Drawer.Title>
                        <p class="paragraph">
                            This component can be used as a replacement for a Dialog on mobile and tablet devices.
                        </p>
                        <p class="paragraph">
                            It uses
                            <a href="https://www.bits-ui.com/docs/components/dialog" class="link" target="_blank">
                                Bits' Dialog primitive
                            </a>
                            under the hood and is inspired by
                            <a
                                href="https://twitter.com/devongovett/status/1674470185783402496"
                                class="link"
                                target="_blank"
                            >
                                this tweet.
                            </a>
                        </p>
                    </div>
                </div>
                <div class="footer">Hello world 123</div>
            </Drawer.Content>
        </Drawer.Portal>
    </Drawer.Root>
</div>

<style>
    .wrapper {
        min-height: 100vh;
        background-color: white;
    }

    :global(.drawer-overlay) {
        position: fixed;
        inset: 0;
        background-color: rgba(0, 0, 0, 0.4);
    }

    :global(.drawer-content) {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        margin-top: 24px;
        display: flex;
        height: 96%;
        flex-direction: column;
        border-radius: 10px 10px 0 0;
        background-color: #f4f4f5; /* bg-zinc-100 */
    }

    :global(.content-wrapper) {
        flex: 1;
        border-radius: 10px 10px 0 0;
        background-color: white;
        padding: 16px; /* p-4 */
    }

    .drag-handle {
        margin: 0 auto 32px;
        height: 6px;
        width: 48px;
        flex-shrink: 0;
        border-radius: 9999px;
        background-color: #d4d4d8;
    }

    :global(.drawer-title) {
        margin-bottom: 16px; /* mb-4 */
        font-weight: 500; /* font-medium */
    }

    .paragraph {
        margin-bottom: 8px; /* mb-2, mb-8 */
        color: #71717a; /* text-zinc-600 */
    }

    .link {
        text-decoration: underline;
    }

    .footer {
        margin-top: auto;
        border-top: 1px solid #e4e4e7; /* border-zinc-200 */
        background-color: #f4f4f5; /* bg-zinc-100 */
        padding: 16px; /* p-4 */
    }
</style>
huntabyte commented 7 months ago

Hey @khromov! if you're using classes, unfortunately, the :global selector is necessary (I believe I saw an issue/PR on the Svelte repo for allowing it to be nested).

If you want the content to stay within the scope of the wrapper you can set the portal prop on the Drawer.Root to null.

khromov commented 7 months ago

Thanks a lot for the answer @huntabyte 🙇