The next/font feature functions perfectly in all areas except for a single specific component

New Experience with Next.js and Tailwind CSS

Exploring the next/font Package

Delving into the realm of the new next/font package has been quite interesting. Following the tutorial provided by Next.js made the setup process smooth sailing. I've incorporated both Inter and a custom local typeface named App Takeoff into my project. To seamlessly integrate these typefaces, I've leveraged Tailwind CSS, assigning Inter to font-sans and App Takeoff to font-display.

A Minor Glitch in the System

After rigorous testing across various files, it appears that everything is functioning flawlessly except within my Modal component. (Refer to the Helpful Update section below for insights on why the issue arises specifically in the Modal component.)

An Illustrative Example

index.tsx

https://i.sstatic.net/8MyTU.png

modal.tsx via index.tsx

https://i.sstatic.net/YrMVA.png

Although the typefaces function seamlessly outside the modal element, they encounter a glitch when embedded within it.

Key Code Snippets:

// app.tsx

import '@/styles/globals.css'
import type { AppProps } from 'next/app'

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

import localFont from 'next/font/local'
const appTakeoff = localFont({
  src: [
    {
      path: '../fonts/app-takeoff/regular.otf',
      weight: '400',
      style: 'normal'
    },
    // additional font paths
  ],
  variable: '--font-app-takeoff'
})

// remaining code snippet continues...
// modal.tsx

import type { FunctionComponent } from 'react'
// more import statements...

const Modal: FunctionComponent<ModalProps> = ({ trigger, place = 'bottom', className, addClass, children }) => {

  // specific functions for modal handling

  return (
    <>
      {/* main functionality of the modal */}
    
    </>
  )
}

export default Modal

I trust this information provides clarity on the issue at hand. Feel free to reach out if further details are required.

Valuable Insight

Credit goes to Jonathan Wieben for shedding light on the root cause behind the malfunction (See Explanation). The essence lies in the scope of applied styles and the utilization of React's Portal component by Headless UI. Any suggestions on altering where the Portal renders or adjusting the style scope would be greatly appreciated. While Jonathan Wieben proposed a solution, my experimentation indicates that it may not align well with Tailwind CSS.

Answer №1

The component you are using to render the dialog appears in a portal, as specified here.

It is recommended to render them as siblings to the root node of your React application for proper DOM ordering and display on top of existing UI elements.

To verify this setup, check if the modal's DOM element is located outside the wrapper from your App component (most likely it is).

If this is the case, the reason why the modal content does not appear with the intended font is because it is rendered outside the font-defining component.

To address this issue, consider defining your font at a higher level, such as in the head section as explained in the Next.js documentation.

Answer №2

I encountered the same issue while using headlessui, tailwind, and nextjs. The solution that was suggested seemed overly complicated for something as simple as a modal. I discovered that adding the font directly into the Modal component solved the problem:

//Modal.tsx
import { Dialog, Transition } from '@headlessui/react';
import { Rubik } from '@next/font/google';

const rubik = Rubik({
  subsets: ['latin'],
  variable: '--font-rubik',
});

type Props = {
  children: React.ReactNode;
  isOpen: boolean;
  closeModal: any;
};

const Modal = ({ children, isOpen, closeModal }: Props) => {
  return (
  <>
  <Transition ...>
    <Dialog ...>
    ...
        <Dialog.Panel
              className={`${rubik.variable} font-sans ...`}>
              ...
        </Dialog.Panel>
    </Dialog>
  </Transition>
  </>
    );
};
export default Modal;

It worked perfectly.

Answer №3

A Fresh Approach

...not without its flaws...

This solution gets the job done, although it falls short of fully harnessing the power of loading next/font. Despite its limitations, it provides a quick fix for now.

The root of the problem lies in @headlessui/react rendering the Modal component as a direct child of the <body> element. To overcome this, we must apply the CSS variables generated by next/font directly to the <body> element, rather than the <div> element within the App component as outlined in the next/font documentation.

Regrettably, incorporating these variables is not as straightforward as with the <div> element. A more traditional JavaScript method is required, involving the addition of classes post-page load using document.querySelector('body') and className.add().

Optional Class Adding Function

In my implementation, I employ a custom function named addClass. While not mandatory, when attempting

body.classList.add(typefaceClasses)
, errors regarding invalid characters were raised.

If you opt for the addClass function, here is how it works:

(function () {
    // Code snippet goes here
})();

Integrating Classes with the Body Element

In the following example, observe our usage of useEffect:

// app.tsx

// Import statements and relevant code snippets go here

What Lies Ahead?

Perhaps in due time, a superior solution will emerge or the Next.js team will address default support for the <body> element.

Answer №4

No problems arise when utilizing the App Directory feature. Since it has officially launched out of beta phase, I strongly advise giving it a try.

Answer №5

// Start of code snippet

/********* including external libraries ****************/
import { Noto_Sans_TC } from '@next/font/google';
import CustomFont from '@next/font/local';
import type { NextPage } from 'next';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import type { ReactElement, ReactNode } from 'react';
import './styles.css';

// End of external libraries section

// Start of internal libraries section

export type NextPageWithLayout<P = unknown, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode;
};

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout;
};

const notoSansTC = Noto_Sans_TC({
  weight: ['300', '400', '700', '900'],
  subsets: ['chinese-traditional'],
  display: 'swap',
});

const chappaFont = CustomFont({
  src: '../public/fonts/chappa-Black.ttf',
  variable: '--font-chappa',
});
const cubic11 = CustomFont({
  src: '../public/fonts/Cubic_11_1.013_R.ttf',
  variable: '--font-cubic11',
});

export default function CustomApp({
  Component,
  pageProps: { session, ...pageProps },
}: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page);

  return (
    <>
      <style jsx global>{`
        .body {
          font-family: ${notoSansTC.style.fontFamily};
        }

        .font-cubic11 {
          font-family: ${cubic11.style.fontFamily};
        }

        .font-chappa {
          font-family: ${chappaFont.style.fontFamily};
        }
      `}</style>
      <Head>
        <title>Welcome</title>
      </Head>
      <div
        className={`${chappaFont.variable} ${cubic11.variable} ${notoSansTC.className}`}
      >
        {getLayout(<Component {...pageProps} />)}
      </div>
    </>
  );
}

// End of code snippet

This code block includes the usage of Next docs and Next docs

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm looking for guidance on utilizing the NodeRT (Windows.Gaming.Input) module within an electron environment. Can anyone provide some

I'm having trouble importing the Gamepad class from a specific module, as I keep encountering the error message "Invalid arguments, no suitable constructor found." Here is the code snippet in question: const { Gamepad } = require('@nodert-win10-2 ...

What is the best way to extract information from a JSON object?

I am currently utilizing the JSON.js library provided by JSON.org. <% JSONReturn = GetDistance(Sample) // this function returns a string in JSON format (specifically from the ArcGIS server Solve Route function) JSONObject = JSON.parse(JSONReturn,"Tota ...

What is the correct way to utilize "data:" in a jQuery AJAX call?

There seems to be an issue with my code within the deletePost function. The problem lies in the fact that $_GET['title'] is empty. Although I set the title value in the ajax using postTitle: $(this).siblings("h3.blog").text(), it doesn't see ...

Automating Internet Explorer using VBA to click a button

I'm currently working on automating tasks on a website using VBA, specifically an online banking system where I am trying to export Transaction History data into a .csv file. Everything seems to be running smoothly until I reach the final Export butto ...

Verify the ng-if condition for a specific value and display an alternative option if the condition is not

When obtaining a response from the server in JSON format (containing color.mix and color.pure), it is passed directly to the template. In this template, I need to display a value if it exists or show another value if it does not. <span ng-if="color.mix ...

Having trouble with your Javascript Ajax call?

I've been attempting to make a POST request using Ajax, but I keep encountering an error with status code 0. Strangely, all the request parameters seem to be functioning correctly in the Advanced REST Client. Here's My Code Snippet: <button& ...

How to Use CSS to Align an Image in a Header

I'm struggling to position an image on the top right corner of my page, specifically in the header. Despite searching for help on Stack Overflow and other online resources, I can't seem to figure it out. Currently, here is what I have: https://i ...

What is the best method for enabling HTML tags when using the TinyMCE paste plugin?

After spending countless hours searching for a solution, I am still puzzled by this problem. My ultimate goal is to have two modes in my powerful TinyMCE editor: Allowing the pasting of HTML or Word/OpenOffice text with all styles and formatting attribu ...

bootstrap for building responsive websites

I am trying to modify the width of an input from 100% to 50%, and position it in the center of the page so that it remains responsive when resizing the browser window. <!DOCTYPE html> <html> <head> <title>test</title&g ...

Webpack has successfully built the production version of your ReactJS application. Upon review, it appears that a minified version of the development build of React is being used

Currently, I am implementing Reactjs in an application and the time has come to prepare it for production. In my package.json file, you can see that there is a "pack:prod" command which utilizes webpack along with a specific webpack.config.js file to build ...

Reset input field when checkbox is deselected in React

How can I bind value={this.state.grade} to clear the input text when the checkbox is unchecked? The issue is that I am unable to modify the input field. If I were to use defaultValue, how would I go about clearing the input box? http://jsbin.com/lukewahud ...

How can we identify if the user is utilizing a text-input control?

Incorporating keyboard shortcuts into my HTML + GWT application is a goal of mine, but I am hesitant about triggering actions when users are typing in a text area or utilizing the keyboard for select menu operations. I am curious if there exists a method ...

How to eliminate all special characters from a text in Angular

Suppose I receive a string containing special characters that needs to be transformed using filter/pipe, with the additional requirement of capitalizing the first letter of each word. For instance, transforming "@!₪ test stri&!ng₪" into "Test Stri ...

Error: No targets with the name "taskname" were found for the custom Grunt task

Just recently, I decided to create my own custom task and here's the process: Started by making an empty folder named "custom-tasks" in the Document Root Next, I created the actual task file: "mytask.js" Implemented the functionality required for th ...

Observe the present time in a specific nation

Is there an authorized method to obtain and showcase the current accurate GMT time instead of relying on the easily manipulable local time on a computer? I am looking for a reliable way to acquire the current time in hours/minutes, so I can make calculati ...

Ensure that the form is submitted only after confirming it in the modal with react-hook-form

**I am facing an issue with submitting react-hook-form on confirm in a modal component. Whenever the user selects confirm, I need the form to be submitted directly. I have tried writing the modal inside FormSubmitButton. Also, I have tried placing it insi ...

Caution: It is not possible to make changes to a component (`App`) during the rendering of another component (`History

I am currently in the process of creating a tic tac toe game, but I'm encountering an error that is preventing me from updating the history. Despite following a tutorial on skillshare.com and mirroring the steps exactly, the error persists. I must men ...

Is it possible to retrieve the `arguments` objects if one of the parameters is named "arguments"?

This code snippet will output 1: (function (params) { console.log(params); }(1, 2)); The params object has replaced the default arguments. Can we retrieve the original arguments object within the function's scope? ...

Enhance the standard input control in Vue.js by extending it to include features such as

Incorporating vue.js: Can you enhance a standard HTML input without the need for a wrapper element? I am interested in customizing a textarea like so: Vue.component('custom-textarea', { data () => { return { } }, template: &apo ...

Preventing the "save" button from being enabled until a change has been made to at least one input field

I have a page with approximately 20 input fields, along with save and register buttons. Is there a way to activate the "save" button only when a change has been made in at least one of the fields? ...