Edit Profile

Dark Mode

Copy config

Copy and paste the following code into your global.css file to apply the styles.

WARNING: This component is in
Draft
status. This means that it is still in development and may have bugs or missing features. It is not intended to be used in production. You may use it for testing purposes.

Modal

A window overlaid on either the primary window or another modal window, rendering the content underneath inert.

Edit Profile

Make changes to your profile here. Click save when you're done.

Installation

Run the following cli command or copy/paste the component code into your project

qwik-ui add modal
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
import { Modal as HeadlessModal } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';
import { cva, type VariantProps } from 'class-variance-authority';
 
const Root = HeadlessModal.Root;
 
const Trigger = HeadlessModal.Trigger;
 
const Close = HeadlessModal.Close;
 
export const panelVariants = cva(
  [
    'fixed w-full bg-background p-6 text-foreground transition-all backdrop:brightness-50 backdrop:backdrop-blur-sm',
    'data-[closing]:duration-300 data-[open]:duration-300 data-[open]:animate-in data-[closing]:animate-out',
    'backdrop:data-[closing]:duration-300 backdrop:data-[open]:duration-300 backdrop:data-[open]:animate-in backdrop:data-[closing]:animate-out backdrop:data-[closing]:fade-out backdrop:data-[open]:fade-in',
  ],
  {
    variants: {
      position: {
        center:
          'max-w-lg rounded-base shadow-lg data-[state=closed]:fade-out data-[state=open]:fade-in data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=open]:slide-in-from-bottom-2 backdrop:data-[closing]:fade-out backdrop:data-[open]:fade-in',
        top: 'inset-x-0 top-0 mt-0 rounded-b-base border-b data-[closing]:slide-out-to-top data-[open]:slide-in-from-top',
        bottom:
          'inset-x-0 bottom-0 mb-0 rounded-t-base border-t data-[closing]:slide-out-to-bottom data-[open]:slide-in-from-bottom',
        left: 'inset-y-0 left-0 ml-0 h-full max-w-sm rounded-r-base border-r data-[closing]:slide-out-to-left data-[open]:slide-in-from-left',
        right:
          'inset-y-0 right-0 mr-0 h-full max-w-sm rounded-l-base border-l data-[closing]:slide-out-to-right data-[open]:slide-in-from-right',
      },
    },
    defaultVariants: {
      position: 'center',
    },
  },
);
 
type PanelProps = PropsOf<typeof HeadlessModal.Panel> &
  VariantProps<typeof panelVariants>;
 
const Panel = component$<PanelProps>(({ position, ...props }) => {
  return (
    <HeadlessModal.Panel {...props} class={cn(panelVariants({ position }), props.class)}>
      <Slot />
    </HeadlessModal.Panel>
  );
});
 
const Title = component$<PropsOf<'h2'>>(({ ...props }) => {
  return (
    <HeadlessModal.Title
      {...props}
      class={cn('text-lg font-semibold tracking-tight', props.class)}
    >
      <Slot />
    </HeadlessModal.Title>
  );
});
 
const Description = component$<PropsOf<'p'>>(({ ...props }) => {
  return (
    <HeadlessModal.Description
      {...props}
      class={cn('text-sm text-muted-foreground', props.class)}
    >
      <Slot />
    </HeadlessModal.Description>
  );
});
 
export const Modal = {
  Root,
  Trigger,
  Close,
  Panel,
  Title,
  Description,
};

Usage

import { Button, Modal } from '~/components/ui';
<Modal.Root bind:show={show}>
  <Modal.Trigger>Open modal</Modal.Trigger>
  <Modal.Panel>
    <Modal.Title>Title</Modal.Title>
    <Modal.Description>Description</Modal.Description>
    <div>...</div>
    <footer>
      <Button look="primary" onClick$={() => (show.value = false)}>
        Save
      </Button>
    </footer>
    <Modal.Close>
      <LuX class="h-5 w-5" />
    </Modal.Close>
  </Modal.Panel>
</Modal.Root>

Examples

Edit Profile

Make changes to your profile here. Click save when you're done.

Edit Profile

Make changes to your profile here. Click save when you're done.

Edit Profile

Make changes to your profile here. Click save when you're done.

Edit Profile

Make changes to your profile here. Click save when you're done.