SelectDemo
Installation
With Command
npx infoteam-ui-kit@latest add SelectManually
1. Add component file
src/components/Select/Select.tsx
"use client";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import Button from "../Button/Button";
import { cn } from "../utils";
const variantsConfig = {
size: {
small: "",
big: "",
},
divider: {
on: "divide-solid divide-transparent divide-x-2",
off: "",
},
};
const variants = cva("inline-flex rounded-md shadow-sm overflow-clip", {
variants: variantsConfig,
defaultVariants: {
size: "small",
divider: "on",
},
});
export interface SelectProps
extends Omit<
React.SelectHTMLAttributes<HTMLSelectElement>,
"onChange" | "size"
>,
VariantProps<typeof variants> {
options: string[];
value: string;
onChange: (value: string) => void;
}
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, size, divider, value, options, onChange, ...props }, ref) => {
return (
<div>
<select
value={value}
className="hidden"
ref={ref}
onChange={(e) => onChange(e.target.value)}
{...props}
>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<div
className={cn(variants({ size, divider, className }))}
role="group"
>
{options.map((option) => (
<div key={option}>
<Button
variant={option === value ? "fill" : "sub"}
size={size}
onClick={() => onChange(option)}
className={`rounded-none active:scale-100 border-none`}
>
{option}
</Button>
</div>
))}
</div>
</div>
);
}
);
Select.displayName = "Select";
export default Select;
export { variantsConfig };
2. Add imported files
src/components/Button/Button.tsx
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "../utils";
const variantsConfig = {
variant: {
fill: "bg-primary text-white",
outline:
"border border-primary text-primary hover:bg-primary hover:text-white",
sub: "bg-greyLight text-text border border-greyBorder",
},
size: {
small: "px-4 py-2 text-sm font-semibold rounded w-fit",
big: "rounded-md px-6 py-3 font-semibold text-base w-fit",
full: "rounded-xl w-full px-8 py-4 text-lg font-bold",
},
animate: {
on: "active:scale-95 transition",
off: "",
},
};
const variants = cva(
"inline-flex items-center justify-center whitespace-nowrap ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: variantsConfig,
defaultVariants: {
variant: "fill",
size: "small",
animate: "on",
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof variants> {}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(variants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export default Button;
export { variantsConfig };
src/components/utils.ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function extractDefaultVariants<
T extends { [K in keyof T]: { [key: string]: string } }
>(variantsConfig: T): { [K in keyof T]: keyof T[K] } {
return Object.fromEntries(
(Object.entries(variantsConfig) as [keyof T, T[keyof T]][]).map(
([key, value]) => [key, Object.keys(value)[0] as keyof T[keyof T]]
)
) as { [K in keyof T]: keyof T[K] };
}
3. Install dependencies
npm
npm install class-variance-authoritynpm
npm install react