Replies: 8 comments 8 replies
-
This looks good except it doesn't place the magnifying glass inside the input. This is because the classes for styling the input are directly on the input and not on the div surrounding both elements. Here's a screenshot. Considering this, I moved styles to an outer div and allowed the same kind of customization as the input. Some styles need to be on the root div like focus-within (within because we're focusing the input not the div) and alignment then some styles need to be on the input itself like padding to get the click target correct.
This snippet appears as such with icon inside the input. Note though it's not inside the input, it's inside the div which is styled to look like an input. |
Beta Was this translation helpful? Give feedback.
-
This is how i was able to get the icon in the inputarea
|
Beta Was this translation helpful? Give feedback.
-
I did this way,
and then can use like this:
|
Beta Was this translation helpful? Give feedback.
-
My solution: import React from 'react'
import { SearchIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
const separatePaddingClasses = (className: string | undefined) => {
const inputClassesPrefixes = [
'p-',
'px-',
'py-',
'pl-',
'pr-',
'pt-',
'pb-',
'placeholder:',
]
const bothElementsClassesPrefixes = ['bg-']
const allClasses = className ? className.split(' ') : []
const bothElementsClasses = allClasses.filter((currentClass) =>
bothElementsClassesPrefixes.some((prefix) =>
currentClass.startsWith(prefix),
),
)
const inputClasses = allClasses.filter((currentClass) =>
inputClassesPrefixes.some((prefix) => currentClass.startsWith(prefix)),
)
const otherClasses = allClasses.filter(
(currentClass) =>
!inputClassesPrefixes.some((prefix) => currentClass.startsWith(prefix)),
)
return {
inputClasses: [...inputClasses, ...bothElementsClasses].join(' '),
otherClasses: [...otherClasses, ...bothElementsClasses].join(' '),
}
}
const SearchInput = React.forwardRef<HTMLInputElement, InputProps>(
({ className, placeholder, ...props }, ref) => {
const { inputClasses, otherClasses } = separatePaddingClasses(className)
return (
<div
className={cn(
'relative flex rounded-lg border border-input bg-transparent pr-3 text-sm text-input shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-input-placeholder focus-within:border-primary focus:outline-none disabled:cursor-not-allowed disabled:opacity-50',
otherClasses,
)}
>
<SearchIcon className="absolute right-4 top-1/2 z-10 -translate-y-1/2 transform text-primary" />
<input
type="text"
placeholder={placeholder}
className={cn(
'w-full rounded-bl-lg rounded-tl-lg border-0 py-2.5 pl-3 outline-none',
inputClasses,
)}
ref={ref}
{...props}
/>
</div>
)
},
)
SearchInput.displayName = 'Search'
export { SearchInput } The |
Beta Was this translation helpful? Give feedback.
-
You should be able to just compose it as such: import { inputVariants } from "@/components";
import React from "react";
import { SearchIcon } from "lucide-react";
export const Search: React.FC = () => {
return (
<label
className={inputVariants({
className: "[&:has(:focus-visible)]:ring-ring flex items-center p-0 [&:has(:focus-visible)]:ring-2",
})}
>
<span className="sr-only">Search</span>
<SearchIcon className="size-4" />
<input
type="search"
placeholder="Search"
className="size-full ml-2 border-none bg-transparent focus:outline-none"
/>
</label>
);
}; |
Beta Was this translation helpful? Give feedback.
-
I've just developed a solution that enhances input components. This solution allows for the seamless integration of icons with inputs, particularly adding support for icons in password inputs, complete with Caps Lock indication and eye icon toggling. "use client";
import * as React from "react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { ArrowBigUpDash, EyeIcon, EyeOffIcon } from "lucide-react";
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
Icon?: React.ComponentType<React.SVGProps<SVGSVGElement>>;
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ Icon, className, type, ...props }, ref) => {
const [showPassword, setShowPassword] = React.useState(false);
const [capsLockActive, setCapsLockActive] = React.useState(false);
const handleKeyPress: React.KeyboardEventHandler<HTMLInputElement> = (
event
) => {
const capsLockOn = event.getModifierState("CapsLock");
setCapsLockActive(capsLockOn);
};
const togglePasswordVisibility = () => setShowPassword(!showPassword);
const inputClasses = cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
Icon && "pl-10",
type === "password" && (!capsLockActive ? "pr-8" : "pr-16"),
className
);
return (
<div className={cn("relative", className)}>
{Icon && (
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<Icon />
</div>
)}
<input
type={type === "password" && showPassword ? "text" : type}
className={inputClasses}
onKeyDown={handleKeyPress}
ref={ref}
{...props}
/>
{type === "password" && (
<div className="absolute right-0 flex items-center pr-3 -translate-y-1/2 top-1/2 gap-x-1">
{showPassword ? (
<EyeOffIcon
className="cursor-pointer"
onClick={togglePasswordVisibility}
size={20}
/>
) : (
<EyeIcon
className="cursor-pointer"
onClick={togglePasswordVisibility}
size={20}
/>
)}
{capsLockActive && type === "password" && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<ArrowBigUpDash size={20} />
</TooltipTrigger>
<TooltipContent>
<p>Caps Lock is on!</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
)}
</div>
);
}
);
Input.displayName = "Input";
export { Input }; |
Beta Was this translation helpful? Give feedback.
-
@F-47 Thanks for the implementation, it's great! I changed the Icon prop to be Also, in the outermost div, I added |
Beta Was this translation helpful? Give feedback.
-
This is what I did with my implimentation, this way you can customize the icon however you like. For example I can add a
|
Beta Was this translation helpful? Give feedback.
-
Do there have official way to do the input with icon?
I got
my implementation but I would like to know is there have the proper way to do it?
Beta Was this translation helpful? Give feedback.
All reactions