shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
70.42k stars 4.23k forks source link

Unable to apply local fonts to PopoverContent #138

Closed iljapanic closed 1 year ago

iljapanic commented 1 year ago

I am using the Popover.tsx component, and while the behavior and Tailwind styling are functioning correctly, I am experiencing difficulties applying local fonts to the component. Despite adding the font-sans class to all classNames within the Popover component and its child components, the utility class does not seem to affect any content inside PopoverContent. PopoverTrigger applies the custom font-family without any issues.

Please find the relevant code snippets below.

Popover.tsx

'use client'

import * as React from 'react'
import * as PopoverPrimitive from '@radix-ui/react-popover'

import { cn } from '@/lib/utils'

const Popover = PopoverPrimitive.Root

const PopoverTrigger = PopoverPrimitive.Trigger

const PopoverContent = React.forwardRef<
  React.ElementRef<typeof PopoverPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
  <PopoverPrimitive.Portal>
    <PopoverPrimitive.Content
      ref={ref}
      align={align}
      sideOffset={sideOffset}
      className={cn(
        'animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 border-gray-3 z-50 rounded border bg-white p-4 font-sans text-gray-900 shadow-md outline-none',
        className,
      )}
      {...props}
    />
  </PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName

export { Popover, PopoverTrigger, PopoverContent }

Component usage (redacted for clarity):

<Popover>
          {/* FILTER TRIGGER */}
          <PopoverTrigger>
            <Button variant="ghost">
              <SlidersHorizontal size={20} strokeWidth={1} className="mr-2" />
              Filters
            </Button>
          </PopoverTrigger>

          {/* FILTER CONTENT */}
          <PopoverContent>
            <div className="font-sans">
              {/* INACTIVE SDGs */}
              <h4 className="font-sans text-base">SDGs</h4>

            </div>
          </PopoverContent>
</Popover>

Here is the rendered result:

Cap 2023-03-23 00 35 49 -  Google Chrome (Resolve—Convergence)@2x

Here is my _app.js where the local fonts are loaded (redacted for clarity):

import localFont from 'next/font/local'
import PlausibleProvider from 'next-plausible'

import '@/styles/globals.css'

const CMUSerif = localFont({
  variable: '--font-cmu-serif',
  src: [
    {
      path: '../assets/fonts/cmu-serif-roman.woff',
      weight: '400',
      style: 'normal',
    },

    …
  ],
})

const HKGrotesk = localFont({
  variable: '--font-hk-grotesk',
  src: [
    {
      path: '../assets/fonts/HKGrotesk-Light.woff2',
      weight: '300',
      style: 'normal',
    },

    …
  ],
})

function MyApp({ Component, pageProps }) {
  return (
    <PlausibleProvider
    >
      <main className={`${CMUSerif.variable} ${HKGrotesk.variable} font-sans`}>
        <Component {...pageProps} />
      </main>
    </PlausibleProvider>
  )
}

export default MyApp

Any help or tips are appreciated 🙌

krishraiturkar commented 1 year ago

Sorry I don't know react

buraksakalli commented 1 year ago

@iljapanic, can you try the following solution?

function MyApp({ Component, pageProps }) {
  return (
<>
  <style jsx global>{`
        :root {
          --font-cmu-serif: ${CMUSerif.variable};
          --font-hk-grotesk: ${HKGrotesk.variable}
        }
      `}
  </style>
    <PlausibleProvider
    >
      <main className={`${CMUSerif.variable} ${HKGrotesk.variable} font-sans`}>
        <Component {...pageProps} />
      </main>
    </PlausibleProvider>
</>
  )
}
iljapanic commented 1 year ago

Thank you @buraksakalli, this workaround seems to have resolved the issue for me! 🙌

It seems like a clean solution as well, so I'm closing this issue.

Amirthananth commented 1 year ago

@buraksakalli Is this still a valid solution ?

I am using NextJS 13 with src directory and tailwind. But, even after setting up the style for global via :root, the default font is applied across the whole website except Dialog component. Any help ?

moinbukhari commented 1 year ago

Yup having the exact same issue

moinbukhari commented 1 year ago

ended up making my own component, you can check it out at:

https://gist.github.com/moinbukhari/cce67d0e0b9ff3dfc3ab1093a0e771bb

Amirthananth commented 1 year ago

That's amazing. But I am worried that it might happen for every other component. I ended up changing the project to App router. Apparently this problem exists only on pages router as the pages are rendered differently.

Eyon42 commented 11 months ago

I still had issues with the proposed solution. What ended up working was to also add the font variable to the <body/> tag in document.tsx

What was happenning for some elements was that they where outside of <main/>, where I was adding the variable.

kirtirajsinh commented 10 months ago

I still had issues with the proposed solution. What ended up working was to also add the font variable to the <body/> tag in document.tsx

What was happenning for some elements was that they where outside of <main/>, where I was adding the variable.

hi, Thanks for sharing this. this worked out for me as well. but Didn't get it. I had added the font in the _app.js inside which the whole app is wrapped.

sunilkalikayi commented 7 months ago

I still had issues with the proposed solution. What ended up working was to also add the font variable to the <body/> tag in document.tsx

What was happenning for some elements was that they where outside of <main/>, where I was adding the variable.

Thak you, @Eyon42 , I able to find out the problem through this it

I have applied the font family individually in all popover components.

Here is an example. //sheet.tsx

import { Open_Sans } from 'next/font/google'
const openSans = Open_Sans({
  subsets: ['latin'],
  variable: '--font-sans'
})

const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
  ({ side = 'right', className, children, ...props }, ref) => (
    <SheetPortal>
      <SheetOverlay />
      <SheetPrimitive.Content
        ref={ref}
        className={cn(sheetVariants({ side }), openSans?.variable, 'font-sans', className)}
        {...props}
      >
        {children}
        <SheetPrimitive.Close className="absolute left-4 sm:left-7 top-[20px] sm:top-[39px] rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100  disabled:pointer-events-none ">
          <div className="hidden sm:block">
            <CloseIcon fill="#333333" />
          </div>
          <div className="block sm:hidden">
            <CloseIcon fill="#333333" width={11.35} height={11.35} />
          </div>
        </SheetPrimitive.Close>
      </SheetPrimitive.Content>
    </SheetPortal>
  )
)
SheetContent.displayName = SheetPrimitive.Content.displayName
Eyon42 commented 7 months ago

Another important caveat is that fonts in _document.tsx are not accounted for the bundle in Next.js. So you will also need to use the fonts in _app or in the pages for it to be bundled at build.

I had multiple fonts so i ended up adding empty spans referencing the fonts i needed at _app.tsx

Manas-E commented 4 months ago

I still had issues with the proposed solution. What ended up working was to also add the font variable to the <body/> tag in document.tsx What was happenning for some elements was that they where outside of <main/>, where I was adding the variable.

Thak you, @Eyon42 , I able to find out the problem through this it

I have applied the font family individually in all popover components.

Here is an example. //sheet.tsx

import { Open_Sans } from 'next/font/google'
const openSans = Open_Sans({
  subsets: ['latin'],
  variable: '--font-sans'
})

const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
  ({ side = 'right', className, children, ...props }, ref) => (
    <SheetPortal>
      <SheetOverlay />
      <SheetPrimitive.Content
        ref={ref}
        className={cn(sheetVariants({ side }), openSans?.variable, 'font-sans', className)}
        {...props}
      >
        {children}
        <SheetPrimitive.Close className="absolute left-4 sm:left-7 top-[20px] sm:top-[39px] rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100  disabled:pointer-events-none ">
          <div className="hidden sm:block">
            <CloseIcon fill="#333333" />
          </div>
          <div className="block sm:hidden">
            <CloseIcon fill="#333333" width={11.35} height={11.35} />
          </div>
        </SheetPrimitive.Close>
      </SheetPrimitive.Content>
    </SheetPortal>
  )
)
SheetContent.displayName = SheetPrimitive.Content.displayName

Thanks @sunilkalikayi and @Eyon42 , I was using Dialog component in Next.js pages dir, and it was not applying fonts to the dialog component but this solution worked for me.