yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆

[Next js] input type='date' width 적용 이슈 본문

적어보자 에러 일지

[Next js] input type='date' width 적용 이슈

yehey 2024. 1. 14. 17:14

Issue

Input 컴포넌트를 styled-component로 커스텀하여 사용하는 중, input type='date' 를 사용하여 날짜를 선택할 수 있게 하려 했다.
데스크탑 웹에서 테스트 및 개발을 하고 있기 때문에 모바일로 확인해서 볼 기회가 없었는데, 최근 테스트를 하며 기대한 것과 다르게 input 의 width가 설정해둔 100%가 아닌 특정 값으로 고정되어있었다. (테스트 기기는 아이폰 13pro, safari, chrome 모두 동일하게 출력됐다.)

왼쪽: 개발자 도구 / 오른쪽: ios

 

100%로는 지정되지 않는데, 정확한 값을 넣으면 또 되고,,, 그치만 내가 원하는건 반응형으로 딱 절반 크기의 width가 될 수 있도록 하고 싶었다.

우선 같은 이슈를 가진 사람들은 어떻게 해결했는지 찾아본 결과..

 

https://github.com/mapbox/assembly/issues/540

 

On mobile Safari, date input is not same width as other inputs · Issue #540 · mapbox/assembly

 

github.com

display:block; width:100%를 통해 해결할 수 있지만 type='date' 를 사용하지 않거나, type='date' 의 스타일링을 막는 방법이 있었다.
display:block; width:100% 참고로 이건 내 케이스에서는 먹히지 않았다. 그래서 2가지 방법을 적용해봤다.

 

Solution 1 : prevent appearance

그리 권장하는 방법은 아니지만, 네이티브로 input type="date" 에 적용되어있는 스타일을 none으로 두고 리셋한다.

/* gloabl css file */

  input[type="date"]{
    appearance:none ;
    -webkit-appearance: none;
    -moz-appearance: none;
  }

 

나는 global style을 정의하는 부분에 input type="date"인 경우에만 appearance:none 을 추가해주었다.

 

원하는대로 input width 가 100%로 설정되었다.

 

Solution 2: react-datepicker 라이브러리 사용

input 태그를 스타일링 해서 사용하는 방법 외에 외부 datepicker 라이브러리를 설치, 사용하는 방법이다.
나는 react-datepicker 라이브러리를 사용했다.

 

https://reactdatepicker.com

 

React Datepicker crafted by HackerOne

 

reactdatepicker.com

npm install react-datepicker --save

//typescript 사용하는 경우 추가
npm install @types/react-datepicker --save

 

react-datepicker 도 내장된 input이 있지만 해당 부분을 inline 으로 처리해서 input은 보이지 않게 하고 datepick 부분만 뜨게 했다.
date pick 부분은 커스텀 버튼으로 컨트롤하도록!

interface IDatePickerButtonProps {
  color?: string;
  onChange: (date: Date, name: string) => void;
  label?: string;
  name: string;
  selected: string;
}

function DatePickerButton({ label, name, onChange, selected, color = theme.color.WHITE }: IDatePickerButtonProps) {
  const [isOpen, setIsOpen] = useState(false);

  const handleChange = (date: Date) => {
    setIsOpen(!isOpen);
    onChange(date, name);
  };
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    setIsOpen(!isOpen);
  };

  return (
    <Wrapper>
      {label && <Label>{label}</Label>}
      <StyledButton color={color} onClick={handleClick}>
        {selected}
      </StyledButton>
      {isOpen && (
        <DateWrapper isOpen={isOpen} hasLabel={!!label}>
          <ReactDatePicker name={name} locale={ko} onChange={handleChange} dateFormat="yyyy-MM-dd" inline />
        </DateWrapper>
      )}
    </Wrapper>
  );
}
export default DatePickerButton;

const Wrapper = styled.div`
  display: flex;
  flex-direction: column;
  width: 100%;
  position: relative;
  z-index: 10;
`;

const Label = styled.label`
  font-size: ${theme.font.fontSize[16]};
  font-weight: ${theme.font.fontWeight.semibold};
  color: ${theme.color.GREY[200]};
  margin-bottom: 0.8rem;
  width: 100%;
`;

const StyledButton = styled.button<{ color: string }>`
  padding: 1.2rem;
  width: 100%;
  height: 4rem;
  border-radius: 8px;
  margin-bottom: 1.5rem;

  font-size: ${theme.font.fontSize[14]};
  font-weight: ${theme.font.fontWeight.regular};
  color: ${theme.color.GREY[200]};
  background-color: ${(props) => props.color};

  border: none;
  outline: none;
`;

const DateWrapper = styled.div<{ isOpen: boolean; hasLabel: boolean }>`
  position: absolute;
  top: ${(props) => (props.hasLabel ? '7rem' : '4.5rem')};
  display: flex;
  flex-direction: column;
  width: 100%;
  /* background-color: transparent; */

  border-radius: 0.8rem;
  box-shadow: 0px 1px 4px 0px ${theme.color.GREY[300]};

  height: ${(props) => (props.isOpen ? 'none' : 0)};
  max-height: ${(props) => (props.isOpen ? 'none' : 0)};
  overflow: ${(props) => (props.isOpen ? 'visible' : 'hidden')};
  z-index: 15;

  @keyframes dropdown {
    0% {
      transform: translateY(-5%);
    }
    100% {
      transform: translateY(0);
    }
  }
  animation: dropdown 1s ease;
`;

 

IDatePickerButtonPropsReactDatePickerProps 를 extend 하도록 할 수 있었지만 selected,onChange 가 타입이 맞지 않아서 적용하지 않았다.

 

 

적용하면 달력 모양이 기본 내장 datepicker 와는 다르다. 저 부분도 수정할 수 있지만 아직 적용하지 않았다.

 

고민중인 부분은 열렸을 때 달력 스타일이 기본 input이 더 낫다는 생각..

react-datepicker는 달력이 너무 작다. 커스텀 하는 방법도 있지만 그래도 기본 input이 나아보이는...

그치만 appearance:none 을 함부로 줘도 되는가? 에 대한 고민은 떨칠 수 없다...


Error Review

간단한 해결방법과 적당한 해결방법을 찾았으니 둘 중 하나를 선택할 일만 남았다.

react-datepicker를 사용한다면 달력을 modal 처럼 portal로 띄워 구성하는 방법을 고려중이다. 달력 크기를 키워야 사용자가 날짜를 선택할 때 편하니까.

 

테스트의 중요성을 알았다. 사용할 기기, 다양한 기기에서 테스트를 해봐야 어떤 점을 생각해야하는 지 알게되는 것 같다.

참조

https://www.appsloveworld.com/coding/ios/18/set-width-of-native-html5-date-and-time-pickers-on-ios-devices?expand_article=1

 

[Resolve]-Set width of native html5 date and time pickers on iOS devices

Coding example for the question Set width of native html5 date and time pickers on iOS devices

www.appsloveworld.com

https://github.com/mapbox/assembly/issues/540

 

On mobile Safari, date input is not same width as other inputs · Issue #540 · mapbox/assembly

 

github.com

https://reactdatepicker.com

 

React Datepicker crafted by HackerOne

 

reactdatepicker.com

 

Comments