Next.js Discord

Discord Forum

Components are out of place while my Login page loads

Answered
Sun bear posted this in #help-forum
Open in Discord
Sun bearOP
I have a question. I currently have 2 pages, one is my login page and the other is my sign up page. Both these pages import client components for my input fields but these pages behave differently when it comes to loading.

While my log-in page first displays the input fields out of place and smaller, then after about a second displays them correctly after the page seems to "load", my sign-up page displays the input fields correctly and loads them much faster from the get go. As in the sign up page does not display the input fields out of place, everything loads normally and fast.

The only difference between these 2 pages is the following:

The login page is one single SSR page on which all the required client side components are loaded.
The sign-up page is split into 2 pages, a small SSR page and a bigger client page and is on that page where I import the client components (basically what I do on the login page).

So my question is basically why is it that the same client components load almost instantly on my signup page compared to my login page where they do load instantly but not fully loaded, they are out of place for a second and then they appear normally.

I've attached a screenshot to this thread with my full layout code if you want to have a look at it.
Answered by DirtyCajunRice | AppDir
id bet 10$ that if you made that whole component without any styled components it wouldnt do it
View full answer

116 Replies

did you set your input fields
to a width
to test
@DirtyCajunRice | AppDir to test
Sun bearOP
// InputField.tsx
'use client'
import React from 'react';
import styled from 'styled-components';

interface InputFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
  icon?: React.ReactNode;
}

const InputContainer = styled.div`
  position: relative;
  width: 340px;
  margin-bottom: 0px;
`;

const StyledInput = styled.input`
  width: 100%;
  height: 36px;
  background-color: var(--input-field);
  color: var(--text-bright);
  border: 0.4px solid var(--border);
  border-radius: 4px;
  padding: 0 12px 0 36px; // Adjusted for icon

  &:focus {
    outline: none;
    border-color: var(--brand-green);
  }
`;

const IconWrapper = styled.div`
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
`;

const InputField: React.FC<InputFieldProps> = ({ icon, ...props }) => {
    return (
      <InputContainer>
        {icon && <IconWrapper>{icon}</IconWrapper>}
        <StyledInput {...props} />
      </InputContainer>
    );
  };  

export default InputField;

I think they are already set to a fixed size (otherwise the rectnagle would shrink them or stretch them for some reason).
oh lawd
i keep forgetting you are using css in js
Sun bearOP
I don't like typescript
tailwind or however it's called
doesn’t mean you need to use css-in-js
styled components is the problem
not the direct css setting
@DirtyCajunRice | AppDir styled components is the problem
Sun bearOP
Why is styled components a problem ? From what I understand it helps when you want to have your codebase modular if you are working with custom components.
since nextjs properly uses ssr, EVEN FOR CLIENT COMPONENTS, styledComponents are now out of date and arent great for nextjs
@DirtyCajunRice | AppDir yep. in **client only components**
Sun bearOP
But hold on, I'm using these styled components on my sign-up page as well, how comes the same issue doesn't occur ?
I can share more code from both pages if you want to have a look and maybe we can figure out why things work better on my sign-up page
@Sun bear But hold on, I'm using these styled components on my sign-up page as well, how comes the same issue doesn't occur ?
dont know. client side cache could be different. thats the problem with css-in-js
id bet 10$ that if you made that whole component without any styled components it wouldnt do it
Answer
@DirtyCajunRice | AppDir id bet 10$ that if you made that whole component without any styled components it wouldnt do it
Sun bearOP
Hehe, actually I think we can test that theory. Give me 2 minutes.
@Sun bear Hehe, actually I think we can test that theory. Give me 2 minutes.
remember to stop your app, delete your .next folder, and clear your browser cache after removing css-in-js components
@DirtyCajunRice | AppDir id bet 10$ that if you made that whole component without any styled components it wouldnt do it
Sun bearOP
Well it looks like you were right, although the icons and the logo take ages to load for some reason.
But umm what would you recommend using instead of styled components in my case ? Like what would be the equivalent ?
For the icons maybe you can help me fix that, I am using a component which is using next themes to switch based on the current theme:
// EmailIcon.tsx
'use client'
import { useTheme } from 'next-themes';
import Image from 'next/image';

import darkModeEmailIcon from '/public/Icons/LoginFormIcons/DarkMode/Email Login Icon.svg';
import lightModeEmailIcon from '/public/Icons/LoginFormIcons/LightMode/Email Login Icon.svg';

const EmailIcon = () => {
  const { resolvedTheme } = useTheme();
  const iconSrc = resolvedTheme === 'dark' ? darkModeEmailIcon : lightModeEmailIcon;

  return (
    <div className="absolute left-4 top-1/2 transform -translate-y-1/2 flex items-center justify-center" style={{ width: '18px', height: '18px' }}>
      <Image
        src={iconSrc}
        alt="Email Icon"
        width={18}
        height={18}
        layout="fixed"
      />
    </div>
  );
};

export default EmailIcon;

I must be doing something wrong here I guess
I think I know what happens, because I've actually tested this theory. When the page loads it loads the light theme version of the icon, which is basically an svg file with the colour for the light mode theme.

What should happen instead is if the app is in dark mode it should load the dark mode icon directly, not load the light mode icon first and then switch, cause I think that's the issue. I don't even know why it's doing it like that.
Could be related to the fact that the page itself is in SSR but the theme works so I don't understand why it can't load the dark mode icons directly if the theme is dark mode, like why does it do it like it does instead and I want to know if there is a workaround to fix it if you know.
you can just do the equivalent directly
Sun bearOP
Awesome that means I should be able to just update the components to not use that.
const StyledInput = (style: Record<string, string> = {}) => (
  <input
    style={{
      width: "100%",
      …style
    }}
  />
^
ts is a bitch to type from my phone that took ages
@DirtyCajunRice | AppDir ts is a bitch to type from my phone that took ages
Sun bearOP
Oh man I'm so sorry do not worry I can just use GPT and I'm sure it will be able to tell me how to update the code.
Well I think this is pretty much solved now I knows what was causing the issue. If you know how I could go about the issue with the icons not loading the dark theme directly if the website is in dark mode please let me know.
@DirtyCajunRice | AppDir use svgs. seriously
Sun bearOP
I am already using svgs or do you mean like a package ?
@Sun bear I am already using svgs or do you mean like a package ?
you are using different svgs for light and dark?
you are using ACTUAL different icons?
@DirtyCajunRice | AppDir you are using ACTUAL different icons?
Sun bearOP
Yes 😅
or the same icon loaded differently because they have different colors
@DirtyCajunRice | AppDir or the same icon loaded differently because they have different colors
Sun bearOP
Oh, the same icon loaded differently because they have different colours
Sun bearOP
I tried doing it through code like switching the colour of the svg directly but it looked way too complex so I ended up just using different svgs 😄
nono its easy
you have just 1 color for the whole icon at once yeah?
Sun bearOP
Yes, it's either let's say for the sake of simplicity:

if light mode: black
if dark mode: white
right
everywhere it says fill="#000000"
change that to currentColor
so fill="currentColor"
then you can set the color of the wrapping div to the light or dark
and boom
propagates just like text
Sun bearOP
Do I have to do anything weird like adding each icon in a component file or in my globals.css ? Cause that's what I think I saw I had to do when I looked this up initially and I didn't like that cause I'd end up with a giant file with all my icons.
nonono
just fix the .svg
Sun bearOP
Ohh, you mean opening the svg file in vscode and rewriting the color values ?
just make them all currentColor
and it lets the outside decide
Sun bearOP
hmm, it would help if you could show me how to do it for 1 icon and then I can update the rest. I will make a new thread cause I want to give you one more answer point since this is a bit of a different topic than the current thread if you don't mind.

And you don't have to do it now since you're on the phone but when you have some time on the computer if that's okay.
Sun bearOP
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 18">
  <path id="mail_FILL1_wght400_GRAD0_opsz48" d="M81.8-782a1.784,1.784,0,0,1-1.26-.506,1.572,1.572,0,0,1-.54-1.181v-14.625a1.572,1.572,0,0,1,.54-1.181A1.784,1.784,0,0,1,81.8-800h20.4a1.784,1.784,0,0,1,1.26.506,1.572,1.572,0,0,1,.54,1.181v14.625a1.572,1.572,0,0,1-.54,1.181,1.784,1.784,0,0,1-1.26.506ZM92-790.494l10.2-6.272v-1.547L92-792.181l-10.2-6.131v1.547Z" transform="translate(-80 800)" fill="#fff"/>
</svg>

Alrighty then, so here is the code for my email icon svg for example, what do I have to change in here ?
😂
oooo this one is super simple
1 path only
see fill="#fff"
Sun bearOP
Yup
change that to fill="currentColor"
@DirtyCajunRice | AppDir oooo this one is super simple
Sun bearOP
That's awesome cause pretty much all my icons are from the same source so the code should be the same for all of them (I'm using google provided icons)
then save
@DirtyCajunRice | AppDir then save
Sun bearOP
I did that now the icon is black.
si
hold up
lol
in your style={{
Sun bearOP
😄 No worries I just wanted to let you know that I saved
add color: lightmodevarthungy ? "#fff" : "#000"
remember im on phone so im slow 🥲
ah next themes so actually:
color: resolvedTheme === "light" ? "#fff" : "#000"
something like that
or swapped if thats how you have it
but you get the gist
@DirtyCajunRice | AppDir in your style={{
Sun bearOP
And where do I do that exactly ? In my login page or in my email icon component ? Do I still need an email icon component if we're doing it this way now ?
@Sun bear And where do I do that exactly ? In my login page or in my email icon component ? Do I still need an email icon component if we're doing it this way now ?
TBH, i am not sure why you have them manually at all. if you install react-icons you have access to ALL of these as imports
@DirtyCajunRice | AppDir dont gotta swap the svgs around
Sun bearOP
Hmm, I've updated my code but the icon doesn't changes its colour:
'use client'
import { useTheme } from 'next-themes';
import Image from 'next/image';

import emailIcon from '/public/Icons/LoginFormIcons/DarkMode/Email Login Icon.svg';

const EmailIcon = () => {
  const { resolvedTheme } = useTheme();
  const iconColor = resolvedTheme === 'dark' ? '#FFFFFF' : '#646363';

  return (
    <div style={{ marginRight: '12px', color: iconColor }}>
      <Image
        src={emailIcon}
        alt="Email Icon"
        width={18}
        height={18}
        layout="fixed"
      />
    </div>
  );
};

export default EmailIcon;

Also I can use react icons instead as long as I can use the icons from Google through it.
@DirtyCajunRice | AppDir yeah it has all of them. i have a feeling its not working because you are passing an svg through Image component
Sun bearOP
Hmm i need a bit of help. How do I need to modify the code in order to get rid of next image for the svg icons ?
Or would you suggest using the react icons package instead ?
And if so do I still have to have the icon as its own component ?
@Sun bear And if so do I still have to have the icon as its own component ?
nope. it will be a component import from the library
@DirtyCajunRice | AppDir nope. it will be a component import from the library
Sun bearOP
Okay, then just to clarify, when I use my input filed component for example:
// InputField.tsx
'use client'
import React from 'react';
import styled from 'styled-components';

// Define the prop types for InputField
interface InputFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
  icon?: React.ReactNode;
}

const InputContainer = styled.div`
  position: relative;
  width: 340px;
  margin-bottom: 0px;
`;

const StyledInput = styled.input`
  width: 100%;
  height: 36px;
  background-color: var(--input-field);
  color: var(--text-bright);
  border: 0.4px solid var(--border);
  border-radius: 4px;
  padding: 0 12px 0 36px; // Adjusted for icon

  &:focus {
    outline: none;
    border-color: var(--brand-green);
  }
`;

const IconWrapper = styled.div`
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
`;

const InputField: React.FC<InputFieldProps> = ({ icon, ...props }) => {
    return (
      <InputContainer>
        {icon && <IconWrapper>{icon}</IconWrapper>}
        <StyledInput {...props} />
      </InputContainer>
    );
  };  

export default InputField;

And I want to add an icon to it, how do I do it ?

Currently I have the component as you see it and on my login page for example for the email input field I just do this:
   {/* Email Input */}
        <label htmlFor="email" className="sr-only">{page.login.emailLabel}</label>
        <InputField
          id="email"
          type="email"
          name="email"
          placeholder={page.login.emailPlaceholder}
          icon={<EmailIcon />}
          required
        />
And how would the icon know what colour to use based on the current theme ? Would I need to define that in the input field component or somewhere else ?
Sun bearOP
By the way, in exchange for helping me, if you need some help with prototyping for a project (as in mock-ups/product design) just send me a dm and I will do my best to help you too 😁
@Sun bear morning. I went into a coma level of sleep after that message haha
@Sun bear Okay, then just to clarify, when I use my input filed component for example: js // InputField.tsx 'use client' import React from 'react'; import styled from 'styled-components'; // Define the prop types for InputField interface InputFieldProps extends React.InputHTMLAttributes<HTMLInputElement> { icon?: React.ReactNode; } const InputContainer = styled.div` position: relative; width: 340px; margin-bottom: 0px; `; const StyledInput = styled.input` width: 100%; height: 36px; background-color: var(--input-field); color: var(--text-bright); border: 0.4px solid var(--border); border-radius: 4px; padding: 0 12px 0 36px; // Adjusted for icon &:focus { outline: none; border-color: var(--brand-green); } `; const IconWrapper = styled.div` position: absolute; left: 12px; top: 50%; transform: translateY(-50%); `; const InputField: React.FC<InputFieldProps> = ({ icon, ...props }) => { return ( <InputContainer> {icon && <IconWrapper>{icon}</IconWrapper>} <StyledInput {...props} /> </InputContainer> ); }; export default InputField; And I want to add an icon to it, how do I do it ? Currently I have the component as you see it and on my login page for example for the email input field I just do this: js {/* Email Input */} <label htmlFor="email" className="sr-only">{page.login.emailLabel}</label> <InputField id="email" type="email" name="email" placeholder={page.login.emailPlaceholder} icon={<EmailIcon />} required />
you dont need the IconWrapper at all with react-icons
you can use className directly
// types/react.ts
import { IconType } from "react-icons";
export type WithIcon<t = {}> = t & { icon?: IconType };
'use client';
import { ComponentProps, HTMLAttributes, InputHTMLAttributes } from "react";



const InputContainer = ({ style, ...props}: HTMLAttributes<HTMLDivElement>) => {
  return (
    <div
      {...props}
      style={{
        position: 'relative',
        width: '340px',
        marginBottom: `0px`,
        ...style,
      }}
    />
  );
}
InputContainer.displayName = "InputContainer";

const StyledInput = ({ style, className, ...props }: InputHTMLAttributes<HTMLInputElement>) => {
  return (
    <div
      {...props}
      className={`focus:border-none focus:border-[var(--green)] ${className}`}
      style={{
        width: '100%',
        height: '36px',
        backgroundColor: 'var(--input-field)',
        color: 'var(--text-bright)',
        border: '0.4px solid var(--border)',
        borderRadius: '4px',
        padding: '0 12px 0 36px', // Adjusted for icon
        ...style,
      }}
    />
  );
}
StyledInput.displayName = "InputContainer";


const InputField = ({ icon: Icon, ...props }: WithIcon<ComponentProps<typeof StyledInput>>) => {
  return (
    <InputContainer>
      {Icon && <Icon style={{ position: 'absolute', left: '0.75rem', top: '50%', transform: `translateY(-50%)` }} />}
      <StyledInput {...props} />
    </InputContainer>
  );
};
InputField.displayName = "InputField";

export { InputContainer, StyledInput, InputField };

These are the same as your above, without styled components
@Sun bear that should accomplish the same thing.
@DirtyCajunRice | AppDir <@998405690718703696> that should accomplish the same thing.
Sun bearOP
Hey, I'm sorry for the late reply. I will try do that and see how it works. Thank you very much!
@DirtyCajunRice | AppDir ts // types/react.ts import { IconType } from "react-icons"; export type WithIcon<t = {}> = t & { icon?: IconType };
Sun bearOP
Hey, I tried using the code. I did create that react.ts file and the folder like you showed but I get this error inside the updated component. Also what will happen with my email and icon components do I still need them or can I delete them ?
For context here is how my tsconfig file looks like:
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
// components/AuthFieldsProps/EmailIcon.tsx
'use client'
import { useTheme } from 'next-themes';
import Image from 'next/image';

import darkModeEmailIcon from '/public/Icons/LoginFormIcons/DarkMode/Email Login Icon.svg';
import lightModeEmailIcon from '/public/Icons/LoginFormIcons/LightMode/Email Login Icon.svg';

const EmailIcon = () => { 
  const { resolvedTheme } = useTheme();
  const iconSrc = resolvedTheme === 'dark' ? darkModeEmailIcon : lightModeEmailIcon;

  return (
    <div style={{ marginRight: '12px' }}>
      <Image
        src={iconSrc}
        alt="Email Icon"
        width={18}
        height={18}
        layout="fixed"
      />
    </div>
  );
};

export default EmailIcon;

// PasswordIcon.tsx
'use client'
import { useTheme } from 'next-themes';
import Image from 'next/image';

import darkModePasswordIcon from '/public/Icons/LoginFormIcons/DarkMode/Password Login Icon.svg';
import lightModePasswordIcon from '/public/Icons/LoginFormIcons/LightMode/Password Login Icon.svg';

const PasswordIcon = () => {
  const { resolvedTheme } = useTheme();
  const iconSrc = resolvedTheme === 'dark' ? darkModePasswordIcon : lightModePasswordIcon;

  return (
    <div style={{ marginRight: '12px' }}>
      <Image
        src={iconSrc}
        alt="Password Icon"
        width={18}
        height={18}
        layout="fixed"
      />
    </div>
  );
};

export default PasswordIcon;
Sun bearOP
Also why did we had to create that react.ts file ? And why did we call it "react.ts" ? I mean that's quite a bold name for such a small file. Is that just a name you decided to go with for the sake of simplicity or is this file sort of a standard core file when working with react ?

By the way, I apologise in advance if I'm being bothering. I get if some of my questions may sound silly but I'm not a programmer so I'm just trying to make sure that I have at least a high level understanding of the files in my project as it helps me understand how things work, and if something goes wrong it gives me a better chance of figuring things out and come up with solutions or at least formulate my questions better when asking for help.

Thank you very much!