Forms
stable
Inputs Advanced
Use Inputs Advanced by copying the source file or importing it into your UI layer.
Preview
registrypreview
Click or drag to upload
Import
tsx
import { Toggle } from "@/components/ui/inputs-advanced";bash
npx sui add inputs-advancedSource
From components/ui/inputs-advanced.tsx
tsx
// @ts-nocheck
import React from "react";
import * as TogglePrimitive from "@radix-ui/react-toggle";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/src/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";
import { X, Upload } from "lucide-react";
// --- Toggle ---
const toggleVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
{
variants: {
variant: {
default: "bg-transparent",
outline: "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-3",
sm: "h-8 px-2",
lg: "h-10 px-3",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
export const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
));
Toggle.displayName = TogglePrimitive.Root.displayName;
// --- Toggle Group ---
const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants>
>({
size: "default",
variant: "default",
});
export const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center justify-center gap-1", className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
));
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
export const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext);
return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
className,
})
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
);
});
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
// --- Slider ---
export const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;
// --- Input OTP ---
export const InputOTP = ({ length = 6, onChange }: { length?: number; onChange?: (val: string) => void }) => {
const [values, setValues] = React.useState(Array(length).fill(""));
const inputs = React.useRef<(HTMLInputElement | null)[]>([]);
const handleChange = (index: number, value: string) => {
if (value.length > 1) value = value.slice(-1);
const newValues = [...values];
newValues[index] = value;
setValues(newValues);
onChange?.(newValues.join(""));
if (value && index < length - 1) {
inputs.current[index + 1]?.focus();
}
};
const handleKeyDown = (index: number, e: React.KeyboardEvent) => {
if (e.key === "Backspace" && !values[index] && index > 0) {
inputs.current[index - 1]?.focus();
}
};
return (
<div className="flex gap-2">
{values.map((v, i) => (
<input
key={i}
ref={(el) => {
inputs.current[i] = el;
}}
value={v}
onChange={(e) => handleChange(i, e.target.value)}
onKeyDown={(e) => handleKeyDown(i, e)}
className="w-10 h-12 text-center text-lg font-bold border rounded-md bg-background outline-none focus:ring-1 focus:ring-ring"
maxLength={1}
/>
))}
</div>
);
};
// --- Input Tag ---
export const InputTag = ({ tags, setTags, placeholder }: { tags: string[]; setTags: (tags: string[]) => void; placeholder?: string }) => {
const [input, setInput] = React.useState("");
const addTag = () => {
if (input && !tags.includes(input)) {
setTags([...tags, input]);
setInput("");
}
};
const removeTag = (tag: string) => {
setTags(tags.filter((t) => t !== tag));
};
return (
<div className="flex flex-wrap gap-2 p-2 border rounded-md bg-background focus-within:ring-1 focus-within:ring-ring">
{tags.map((tag) => (
<span key={tag} className="flex items-center gap-1 px-2 py-1 rounded-md bg-secondary text-secondary-foreground text-xs font-medium">
{tag}
<button onClick={() => removeTag(tag)} className="hover:text-destructive">
<X className="h-3 w-3" />
</button>
</span>
))}
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && addTag()}
placeholder={placeholder || "Add tag..."}
className="flex-1 bg-transparent outline-none text-sm min-w-[100px]"
/>
</div>
);
};
// --- File Upload ---
export const FileUpload = ({ onUpload }: { onUpload?: (files: File[]) => void }) => {
const inputRef = React.useRef<HTMLInputElement>(null);
const [fileNames, setFileNames] = React.useState<string[]>([]);
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const fileList = e.target.files;
const files: File[] = fileList ? Array.from<File>(fileList) : [];
if (files.length > 0) {
setFileNames(files.map((file) => file.name));
onUpload?.(files);
}
};
return (
<div
onClick={() => inputRef.current?.click()}
className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-xl cursor-pointer hover:bg-muted/50 transition-colors"
>
<input type="file" ref={inputRef} onChange={handleFileChange} className="hidden" multiple />
<Upload className="h-8 w-8 text-muted-foreground mb-2" />
<p className="text-sm text-muted-foreground">
{fileNames.length > 0 ? fileNames.join(", ") : "Click or drag to upload"}
</p>
</div>
);
};
Component Info
Slug
inputs-advancedCategory
Forms
Status
stable
Quick Actions
Tags
inputs-advanced