Search code examples
typescriptreact-typescript

React-Typescript: This JSX tag's 'children' prop expects a single child of type 'Element | undefined', but multiple children were provided


I am using react-typescript for my app. For styling I am using Style component. I have decided I will create my custom Hooks Input and Password input. So I first created Input wrapper where I added necessary input fields. After that I have created Password input field. i extended my Password input component props with Input component props. But when I am using Input component wrapper to my password component. I am getting error: This JSX tag's 'children' prop expects a single child of type 'Element | undefined', but multiple children were provided.

I don't know what I am doing wrong.

This is my Input wrapper component

import React from "react";
import styled from "styled-components";
import ErrorBoundary from "components/errorBoundary";

const Container = styled.div`
  position: relative;
`;

const Label = styled.label<{ minimized?: boolean }>`
  display: block;
  color: ${({ theme }) => theme.inputLabelColor};
  font-weight: 400;
  font-size: ${({ minimized }) => (minimized ? "11px" : "16px")};
  margin-bottom: 5px;
  letter-spacing: -0.2px;
  position: absolute;
  transform: translateY(${({ minimized }) => (minimized ? "9px" : "16px")});
  left: 20px;
  top: 0;
  pointer-events: none;
  transition: transform 150ms linear, font-size 150ms linear;
`;

const Error = styled.p`
  color: ${({ theme }) => theme.errorTextColor};
`;

const Description = styled.p`
  color: blue;
`;

export interface IInputWrapperProps {
  label?: string;
  required?: boolean;
  minimizedLabel?: boolean;
  description?: string;
  error?: string;
  wrapperStyle?: React.CSSProperties;
  children?: JSX.Element;
}

export default ({
  label,
  error,
  description,
  children,
  required,
  wrapperStyle,
  minimizedLabel
}: IInputWrapperProps) => {
  return (
    <ErrorBoundary id="InputWrapperErrorBoundary">
      <div style={wrapperStyle}>
        <Container>
          <Label minimized={minimizedLabel}>
            {label} {required && <span style={{ color: "red" }}> *</span>}
          </Label>
          {children}
        </Container>
        {description && <Description>{description}</Description>}
        {error && <Error>{error}</Error>}
      </div>
    </ErrorBoundary>
  );
};

This is my password component

import React, { useState } from "react";
import styled from "styled-components";
import eyeHide from "./eye-svgfiles/eyeHide.svg";
import eyeShow from "./eye-svgfiles/eyeShow.svg";
import InputWrapper, { IInputWrapperProps } from "../wrapper";
const Passwordinput = styled.input`
  border: 2px solid ${({ theme }) => theme.inputBorderColorFaded};
  background: ${({ theme }) => theme.inputBackgroundColor};
  display: block;
  border-radius: 5px;
  box-shadow: none;
  color: ${({ theme }) => theme.inputTextColor};
  height: 52px;
  width: 100%;
  margin: 0;
  padding: 1px 15px;
  &:focus {
    border: 2px solid ${({ theme }) => theme.inputBorderColor};
    outline: 0;
  }
`;
const Svg = styled.div`
  position: absolute;
  left: 50%;
  top: 65%;
  transform: scale(0.8);
`;

export interface IPasswordProps extends IInputWrapperProps {
  onChange: (i: string) => void;
  value?: string | undefined;
}
export default ({ onChange, value, label, error, ...rest }: IPasswordProps) => {
  const [state, setstate] = useState(false);
  return (
    <div>
      <InputWrapper label={label} error={error} {...rest}> //I am getting error in here 
        <Passwordinput
          label={label}
          type={state ? "text" : "password"}
          onChange={e => onChange(e.target.value)}
          value={value}
          error={error}
        />
        <Svg>
          <img
            onClick={() => setstate(state => !state)}
            style={{ cursor: "pointer" }}
            src={state ? eyeShow : eyeHide}
            alt="searchIcon"
          />
        </Svg>
      </InputWrapper>
    </div>
  );
};

Solution

  • Write your interface like this:

    export interface IInputWrapperProps {
      label?: string;
      required?: boolean;
      minimizedLabel?: boolean;
      description?: string;
      error?: string;
      wrapperStyle?: React.CSSProperties;
      children?: JSX.Element|JSX.Element[];
    }
    

    in fact writing:

    children: JSX.Element|JSX.Element[];
    

    The children can be either a single JSX Element or an array of Elements.