ui icon indicating copy to clipboard operation
ui copied to clipboard

feat: added icon support for input fields

Open towhidstack opened this issue 2 years ago • 8 comments

This pull request addresses issue #1562 and introduces the feature of icon support for input fields. Users can now include icons within input fields to enhance visual representation or provide context. Icons can be positioned on the left or right of the input field, providing flexibility for various use cases.

Best regards, Towhid Hasan msedge_TZ44sGKj0D

towhidstack avatar Sep 20 '23 04:09 towhidstack

@TowhidBD is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Sep 20 '23 04:09 vercel[bot]

One thing I would change: Instead of an icon property it is better to have a startIcon and endIcon property. Use case would be a "lock icon" and "eye icon" for password fields.

Generalization: Even better is to have input adornments where you can specify start and end as ReactNodes. With adornments you can also add prefix and suffix easily like for example a "minutes" suffix.

MJomaa avatar Oct 02 '23 07:10 MJomaa

I wonder if there is any way to hide icons on smaller screen, i.e. to provide min width (or screen size) beyond which the icon is visible. Smaller screens can get more width for text.

kachkaev avatar Oct 15 '23 09:10 kachkaev

Somebody will fix? :D

oliwkevich avatar Oct 21 '23 22:10 oliwkevich

I think this "icons" can be something like toggle show password that it's a button, so i think it's better call adornment, and in some cases people would like to use in left and in right position, and following the @kachkaev recomendation i add the border classes to the outer div and some disabled handle too:

import * as React from "react";
import { cn } from "~/lib/utils";

export interface InputProps
  extends React.InputHTMLAttributes<HTMLInputElement> {
  startAdornment?: JSX.Element;
  endAdornment?: JSX.Element;
}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
  ({ className, type, startAdornment, endAdornment, ...props }, ref) => {
    const hasAdornment = Boolean(startAdornment) || Boolean(endAdornment);
    return (
      <>
        {hasAdornment ? (
          <div
            className="flex items-center justify-center gap-2 px-3 h-10 rounded-md border border-input bg-transparent ring-offset-background focus-within:ring-1 focus-within:ring-ring focus-within:ring-offset-2 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50"
            data-disabled={props.disabled}
          >
            {startAdornment && (
              <div className={cn("text-muted-foreground")}>
                {startAdornment}
              </div>
            )}
            <input
              type={type}
              className={cn(
                "flex h-full w-full rounded-md bg-transparent py-2 text-sm file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground shadow-none outline-none border-none focus-visible:outline-none focus-visible:border-none focus-visible:shadow-none",
                className
              )}
              ref={ref}
              {...props}
            />
            {endAdornment && (
              <div className={cn("text-muted-foreground")}>{endAdornment}</div>
            )}
          </div>
        ) : (
          <input
            type={type}
            className={cn(
              "flex h-10 w-full rounded-md border border-input bg-transparent px-4 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
              className
            )}
            ref={ref}
            {...props}
          />
        )}
      </>
    );
  }
);
Input.displayName = "Input";

export { Input };

usage:

<FormField
  control={methods.control}
  name="sequentialCode"
  render={({ field }) => (
    <FormItem className="w-full">
      <FormLabel>Sequential Code</FormLabel>
      <FormControl>
        <Input
          {...field}
          placeholder="Sequential Code"
          endAdornment={
            <Tooltip>
              <TooltipTrigger asChild>
                <HelpCircle className="h-4 w-4 cursor-pointer" />
              </TooltipTrigger>
              <TooltipContent>
                <p>
                  Sequential Code is something cool
                </p>
              </TooltipContent>
            </Tooltip>
          }
        />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>

victorcesae avatar Feb 04 '24 16:02 victorcesae

@victorcesae - This is fantastic and exactly what I was hoping for. I really hope this is merged, it works excellently. Thank you so much.

timreach avatar Feb 23 '24 13:02 timreach

Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.

image

{prefix && (
    <div className={cn('flex justify-center items-center text-muted-foreground pl-3 select-none', typeof prefix === 'string' && 'bg-muted/70 pr-3 border-r border-input')}>{prefix}</div>
)}

UltimateGG avatar May 03 '24 02:05 UltimateGG

Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.

image

{prefix && (
    <div className={cn('flex justify-center items-center text-muted-foreground pl-3 select-none', typeof prefix === 'string' && 'bg-muted/70 pr-3 border-r border-input')}>{prefix}</div>
)}

Perhaps this should be left to the developer to decide? ReactNode should already cover this use case, no?

hafbau avatar Aug 10 '24 10:08 hafbau

Just wanted to +1 and bump this, it'd be super useful to have.

coppinger avatar Sep 22 '24 10:09 coppinger

wanted +1

supgeek-rod avatar Dec 11 '24 09:12 supgeek-rod

Cursor helped me 😂

image

code in below

<div className="flex">
  <div className="flex items-center justify-center px-3 border border-r-0 rounded-l bg-gray-50">
    {payment.pay_due_currency}
  </div>
  <Input className="rounded-l-none" readOnly type="text" value={payment.pay_due_amount} />
</div>

supgeek-rod avatar Dec 11 '24 09:12 supgeek-rod

Cursor helped me 😂

image

code in below


<div className="flex">

  <div className="flex items-center justify-center px-3 border border-r-0 rounded-l bg-gray-50">

    {payment.pay_due_currency}

  </div>

  <Input className="rounded-l-none" readOnly type="text" value={payment.pay_due_amount} />

</div>

Does this do something different to the proposed solution? What's the motivation for sharing? Looks kind of based in your specific implementation.

timreach avatar Dec 11 '24 09:12 timreach

Hi everyone! 👋

I’m excited to share an extension library I’ve built for shadcn/ui, which includes an InputBase component. The API adheres to Radix UI and shadcn/ui conventions, ensuring it’s both intuitive and easy to integrate into your projects.

You can check it out here: https://ui-x.junwen-k.dev/docs/components/input-base

The library also includes other handy components designed to enhance developer productivity. If you find it helpful, I’d be thrilled if you could leave a star—it really helps others discover the project. I’d love to hear your feedback or suggestions, so feel free to share your thoughts! 😊

junwen-k avatar Jan 26 '25 16:01 junwen-k

Wanted + 1

Kinqdos avatar Sep 07 '25 12:09 Kinqdos

This is now available as InputGroup. Thanks for your work on this PR @towhidstack. Appreciate it.

shadcn avatar Oct 15 '25 07:10 shadcn

Thank you legend 🙏

coppinger avatar Oct 17 '25 03:10 coppinger