Styling
okayy ships with sensible defaults that look great out of the box, but every element of the confirmation dialog can be fully customized. You can target elements using CSS data attributes for global styling, or pass className props for one-off adjustments.
Data attribute selectors
Every element in the dialog exposes a data-okayy-* attribute that you can target directly in your CSS. This approach avoids specificity issues since attribute selectors don't compete with class-based utility frameworks.
The full set of available selectors:
[data-okayy]-- the portal root wrapper[data-okayy-overlay]-- the backdrop overlay behind the dialog[data-okayy-dialog]-- the dialog container[data-okayy-content]-- the content area (title + description)[data-okayy-header]-- the header row (icon + title)[data-okayy-icon]-- the variant icon wrapper[data-okayy-title]-- the title text[data-okayy-description]-- the description text[data-okayy-keyword]-- the type-to-confirm wrapper[data-okayy-keyword-label]-- the keyword label text[data-okayy-keyword-input]-- the keyword input field[data-okayy-footer]-- the button row[data-okayy-button]-- all buttons (base selector)[data-okayy-cancel]-- the cancel button[data-okayy-action]-- custom action buttons[data-okayy-confirm]-- the confirm button[data-okayy-spinner]-- the loading spinner
State and variant attributes on the dialog:
[data-state="initial|open|closed"]-- animation state (on overlay and dialog)[data-variant="default|danger|warning|info|success"]-- visual variant[data-layout="default|centered"]-- layout mode[data-size="sm|md|lg|xl|full"]-- size preset[data-custom]-- present when usingconfirm.custom()[data-unstyled]-- present whenunstyled: true
/* The dialog container */
[data-okayy-dialog] {
border-radius: 16px;
}
/* The overlay backdrop */
[data-okayy-overlay] {
background: rgba(0, 0, 0, 0.8);
}
/* The title */
[data-okayy-title] {
font-size: 18px;
}
/* The description */
[data-okayy-description] {
font-size: 14px;
}
/* The confirm button */
[data-okayy-confirm] {
font-weight: 600;
}
/* The cancel button */
[data-okayy-cancel] {
opacity: 0.7;
}className props
For one-off styling that only applies to a specific confirmation, you can pass className and overlayClassName directly in the options object. className applies to the dialog container, while overlayClassName controls the backdrop overlay. These are useful when you need a unique look for a particular confirmation without writing global CSS.
Tailwind CSS
For full Tailwind control, use the unstyled prop on <Confirmer /> to strip all default visual styles, then provide your classes via classNames.
Global Tailwind styling:
<Confirmer
unstyled
defaultOptions={{
classNames: {
dialog: 'bg-white dark:bg-gray-900 rounded-xl p-6 shadow-xl border border-gray-200 dark:border-gray-800 max-w-sm w-full',
overlay: 'bg-black/60 backdrop-blur-sm',
title: 'text-lg font-semibold text-gray-900 dark:text-gray-100',
description: 'text-sm text-gray-500 dark:text-gray-400 mt-2',
confirmButton: 'bg-gray-900 dark:bg-white text-white dark:text-gray-900 px-4 py-2 rounded-lg font-medium hover:opacity-90',
cancelButton: 'border border-gray-200 dark:border-gray-700 px-4 py-2 rounded-lg font-medium hover:bg-gray-50 dark:hover:bg-gray-800',
footer: 'flex justify-end gap-2 mt-6',
},
}}
/>Per-dialog Tailwind styling:
const ok = await confirm({
title: 'Delete project?',
unstyled: true,
classNames: {
dialog: 'bg-red-50 border-red-200 rounded-xl p-6 max-w-sm w-full',
title: 'text-red-900 text-lg font-bold',
confirmButton: 'bg-red-600 text-white px-4 py-2 rounded-lg',
},
});The classNames object supports these keys:
| Key | Element |
|---|---|
| dialog | The dialog container |
| overlay | The backdrop overlay |
| title | The title text |
| description | The description text |
| confirmButton | The confirm button |
| cancelButton | The cancel button |
| actionButton | Custom action buttons |
| icon | The variant icon wrapper |
| content | The content wrapper |
| footer | The button row |
Changing icons
Each confirmation variant (danger, warning, info, success) renders a default icon. You can override these at two levels.
Globally, set the icons prop on the <Confirmer /> component to replace the default icons across your entire app:
<Confirmer
icons={{
danger: <TrashIcon />,
warning: <AlertIcon />,
info: <InfoIcon />,
success: <CheckIcon />,
}}
/>Per-call, pass an icon prop to override the icon for a single confirmation. Icons can be any valid React element -- an SVG component, an emoji string, or a custom component:
Dark mode
okayy supports three theme modes: light, dark, and system. Set the theme prop on <Confirmer /> to control which mode is used:
// Follow OS preference
<Confirmer theme="system" />
// Force dark
<Confirmer theme="dark" />
// Force light
<Confirmer theme="light" />When set to system, okayy automatically detects the .dark class on your <html> element and adjusts accordingly. This works seamlessly with next-themes, tailwind dark mode, or any library that toggles a .dark class -- no additional configuration required.
CSS custom properties
Override these variables on [data-okayy] to customize colors, fonts, and shadows without writing component-level CSS. All variables are set in light mode by default and overridden inside .dark [data-okayy] for dark mode.
| Variable | Description | Light default |
|---|---|---|
--okayy-font | Font family stack | Geist Sans, Inter, system-ui |
--okayy-overlay-bg | Overlay backdrop color | rgba(0, 0, 0, 0.8) |
--okayy-dialog-bg | Dialog background | #ffffff |
--okayy-dialog-shadow | Dialog box-shadow | Multi-layer shadow |
--okayy-dialog-border | Dialog border color | #e5e5e5 |
--okayy-text-color | Primary text color | #0a0a0a |
--okayy-cancel-bg | Cancel button background | transparent |
--okayy-cancel-border | Cancel button border | #e5e5e5 |
--okayy-cancel-text | Cancel button text color | #0a0a0a |
--okayy-cancel-hover-bg | Cancel button hover background | #f5f5f5 |
--okayy-confirm-bg | Confirm button background | #0a0a0a |
--okayy-confirm-border | Confirm button border | #0a0a0a |
--okayy-confirm-text | Confirm button text color | #fafafa |
--okayy-confirm-hover-bg | Confirm button hover background | #171717 |
--okayy-ring-color | Focus ring color | #0a0a0a |
--okayy-icon-color | Variant icon color | #0a0a0a |
--okayy-muted | Muted text/accents | #737373 |
Each variant (danger, warning, info, success) overrides --okayy-confirm-*, --okayy-icon-color, and --okayy-ring-color with its own palette.
/* Example: brand-colored confirm button */
[data-okayy] {
--okayy-confirm-bg: #4f46e5;
--okayy-confirm-border: #4f46e5;
--okayy-confirm-hover-bg: #4338ca;
--okayy-ring-color: #4f46e5;
}Responsive behavior
On viewports narrower than 640px, the dialog automatically switches to a bottom sheet layout — sliding up from the bottom with a drag handle indicator. Buttons stack vertically with 44px minimum touch targets, and safe-area insets are respected for devices with notches.
No configuration is needed — the responsive layout is handled entirely in CSS via @media (max-width: 639px).
Animations
okayy uses CSS keyframe animations controlled by the data-state attribute:
data-state="initial"— dialog is mounted but not yet visibledata-state="open"— animating in (scale + fade on desktop, slide up on mobile)data-state="closed"— animating out
When prefers-reduced-motion: reduce is active, scale and slide animations are replaced with a simple fade, respecting the user's accessibility preference.
RTL support
Set dir="rtl" on individual dialogs or globally via the <Confirmer dir="rtl" /> prop. The dialog layout, button order, and text alignment all flip automatically. Use dir="auto" to detect direction from the page's <html> element.