Shadcn calendar is broken in admin views
Closed this issue · 3 comments
Describe the Bug
The shadcn calendar breaks due to missing tailwind reset.

What would be the way to fix this? Are there any known workarounds to this?
Link to the code that reproduces this issue
https://github.com/siimsams/payload-shadcn
Reproduction Steps
How?
I followed the official guide regarding getting tailwind and shadcn to work in payload.
https://payloadcms.com/posts/guides/how-to-setup-tailwindcss-and-shadcn-ui-in-payload
https://ui.shadcn.com/docs/components/calendar
Reproduction steps
pnpm ipnpm run dev- http://localhost:3000/admin/test
- Click on the
Which area(s) are affected? (Select all that apply)
area: ui
Environment Info
➜ payload-shadcn git:(main) ✗ pnpm payload info
> payload-shadcn@1.0.0 payload /Users/siimsams/projects/payload-shadcn
> cross-env NODE_OPTIONS=--no-deprecation payload info
Binaries:
Node: 22.16.0
npm: 10.9.2
Yarn: N/A
pnpm: 10.12.3
Relevant Packages:
payload: 3.56.0
next: 15.4.4
@payloadcms/email-nodemailer: 3.56.0
@payloadcms/graphql: 3.56.0
@payloadcms/next/utilities: 3.56.0
@payloadcms/payload-cloud: 3.56.0
@payloadcms/richtext-lexical: 3.56.0
@payloadcms/translations: 3.56.0
@payloadcms/ui/shared: 3.56.0
react: 19.1.0
react-dom: 19.1.0
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
Available memory (MB): 32768
Available CPU cores: 10
I guess this is related: #8878
EDIT:
The workaround in the related issue no longer works.
I'm exploring the examples from here: Roman86/tailwindcss-scoped-preflight#67
I found a workaround.
You just need to do this:
@layer theme {
@import 'tailwindcss/theme.css';
}
@layer base {
[data-twp],
[data-radix-popper-content-wrapper] {
@import 'tailwindcss/preflight.css';
}
[data-twp-reset] {
*,
::after,
::before,
::backdrop,
::file-selector-button {
all: revert-layer;
}
}
}
@layer components;
@layer utilities {
@import 'tailwindcss/utilities.css';
}
@custom-variant dark (&:where(.dark &, [data-theme="dark"] &));
:root {
--radius: 0.65rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
:is(.dark, [data-theme="dark"]) {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-2xs: var(--shadow-2xs);
--shadow-xs: var(--shadow-xs);
--shadow-sm: var(--shadow-sm);
--shadow: var(--shadow);
--shadow-md: var(--shadow-md);
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}And create shadcn wrapper to take advantage of this.
import React from 'react'
interface ShadcnWrapperProps {
children: React.ReactNode
className?: string
}
/**
* Wrapper component that provides scoped preflight styles for shadcn/ui components
* in the Payload admin interface. This ensures shadcn components work properly
* without interfering with existing admin styles.
*/
export const ShadcnWrapper: React.FC<ShadcnWrapperProps> = ({
children,
className = ''
}) => {
return (
<div data-twp className={`${className}`}>
{children}
</div>
)
}
export default ShadcnWrapperAnd then you are able to use it like so anywhere in admin:
import type { AdminViewServerProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import React from 'react'
import { Button } from '../ui/button'
import { Calendar23 } from '../ui/calendar-23'
import { ShadcnWrapper } from './ShadcnWrapper'
export default function CreateOrder({
initPageResult,
params,
searchParams,
}: AdminViewServerProps) {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
className="h-full"
visibleEntities={initPageResult.visibleEntities}
>
<ShadcnWrapper className="flex flex-col gap-4 items-center justify-center p-4">
<h2 className="text-xl font-semibold mb-4">Create Order</h2>
<Button>Create Order</Button>
<div className="space-y-4">
<div>
<h3 className="text-lg font-medium mb-2">Calendar 23</h3>
<Calendar23 />
</div>
</div>
</ShadcnWrapper>
</DefaultTemplate>
)
}I am going to close this as it's a known issue and there is a workaround.
This issue has been automatically locked.
Please open a new issue if this issue persists with any additional detail.