Textarea

장문 입력을 받는 구성 요소입니다.

Example

It can only be viewed in a mobile.

Steps

Prerequisite

Copy Code

components/Textarea/index.tsx
'use client'
 
import { useId } from 'react'
import type {
  DetailedHTMLProps,
  KeyboardEvent,
  ReactNode,
  TextareaHTMLAttributes
} from 'react'
import { cn } from 'utils'
 
export interface Props
  extends DetailedHTMLProps<
    TextareaHTMLAttributes<HTMLTextAreaElement>,
    HTMLTextAreaElement
  > {
  onEnter?: () => void
  info?: ReactNode
  error?: ReactNode
  float?: boolean
  fullWidth?: boolean
}
 
function Textarea({
  onEnter,
  info,
  error,
  fullWidth,
  float,
  placeholder,
  ...props
}: Props) {
  const id = useId()
 
  const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === 'Enter' && !e.shiftKey && !!onEnter) onEnter()
  }
  return (
    <div
      className={cn('inline-block', {
        'w-full': fullWidth,
        relative: !!placeholder
      })}
    >
      <textarea
        {...props}
        id={props.id || id}
        onKeyDown={onKeyDown}
        className={cn(
          'rounded border bg-white p-2 read-only:cursor-default focus:outline-none disabled:cursor-not-allowed dark:bg-neutral-800',
          error
            ? 'border-red-500'
            : 'border-neutral-300 dark:border-neutral-700',
          {
            'w-full': fullWidth,
            'bg-neutral-100': props.disabled,
            'peer placeholder:text-transparent': !!placeholder && float
          }
        )}
        placeholder={placeholder}
        spellCheck={false}
      />
      {!!placeholder && float && (
        <label
          htmlFor={props.id || id}
          className={cn(
            'absolute -top-6 left-0 cursor-text select-none truncate text-sm text-neutral-600 transition-all peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-placeholder-shown:text-neutral-400 peer-empty:left-3 peer-focus:-top-6 peer-focus:left-0 peer-focus:w-full peer-focus:cursor-default peer-focus:text-sm peer-focus:text-neutral-600 dark:text-neutral-400 dark:peer-focus:text-neutral-400',
            props.value ? 'left-0' : 'left-3'
          )}
        >
          {placeholder}
        </label>
      )}
      {(!!error || !!info) && (
        <p
          className={cn(
            'mt-1 text-xs',
            error ? 'text-red-500' : info ? 'text-neutral-400' : undefined
          )}
        >
          {error || info}
        </p>
      )}
    </div>
  )
}
 
export default Textarea

Usage

<Textarea
  value=""
  onChange={(e) => setValue(e.target.value)}
  info={<p>Info</p>}
  error={<p>Error</p>}
  float
  fullWidth
/>

Props

NameTypeDefault
onEnter() => void
infoReactNode
errorReactNode
floatboolean
fullWidthboolean
...propsHTMLTextAreaElement