Coder Social home page Coder Social logo

jaleelb / shadcn-tag-input Goto Github PK

View Code? Open in Web Editor NEW
477.0 5.0 19.0 2.07 MB

A fully-featured tag input component built with shadcn/ui

Home Page: https://emblor.jaleelbennett.com

License: MIT License

CSS 1.34% TypeScript 73.36% JavaScript 0.21% MDX 25.08%
input radix shadcn-ui autocomplete popover react-tag-input tag-input

shadcn-tag-input's Introduction

Screen.Recording.2023-09-01.at.10.32.22.AM.mov

Emblor is a highly customizable, accessible, and fully-featured tag input component built with Shadcn UI.

About

Emblor is built on top of the Input, Popover, Command and Dialog components from Shadcn UI.

Installation

To install Emblor, run the command:

pnpm add emblor

Features

  • Autocomplete: Enable autocomplete suggestions for tags.
  • Validation: Validate tags based on custom rules.
  • Limit: Set a maximum and minimum number of tags.
  • Duplication: Allow or disallow duplicate tags.
  • Character Limit: Define the maximum length of a tag.
  • Sorting: Sort tags alphabetically.
  • Truncation: Truncate tags that exceed a certain length.
  • Popovers: Use popovers to display tags.
  • Keyboard Navigation: Use keyboard shortcuts to interact with the tag input.
  • Customization: Change the appearance and behavior of the tags by passing in a custom tag renderer.
  • Accessibility: Ensure that the tag input is accessible to all users.
  • Drag and Drop: Allow users to reorder tags using drag and drop.
  • Read-only Mode: Prevent users from editing the tag input.
  • Delimiters: Define custom delimiters for separating tags.

Usage

Here's a sample implementation that initializes the component with a list of initial tags and suggestions list. Apart from this, there are multiple events, handlers for which need to be set.

The example below uses tailwindcss @shadcn/ui tailwind-merge clsx:

import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Tag, TagInput } from 'emblor';
import Link from 'next/link';
import { Button, buttonVariants } from '@/components/ui/button';
import { z } from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import React from 'react';
import { toast } from '@/components/ui/use-toast';

const FormSchema = z.object({
  topics: z.array(
    z.object({
      id: z.string(),
      text: z.string(),
    }),
  ),
});

export default function Hero() {
  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
  });

  const [tags, setTags] = React.useState<Tag[]>([]);

  const { setValue } = form;

  function onSubmit(data: z.infer<typeof FormSchema>) {
    toast({
      title: 'You submitted the following values:',
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(data, null, 2)}</code>
        </pre>
      ),
    });
  }

  return (
    <section className="z-10 max-w-5xl w-full flex flex-col items-center text-center gap-5">
      <div className="z-10 w-full flex flex-col items-center text-center gap-5">
        <h1 className="scroll-m-20 text-4xl font-bold tracking-tight">Shadcn Tag Input</h1>
        <p className="text-muted-foreground max-w-[450px]">
          An implementation of a Tag Input component built on top of Shadcn UI&apos;s input component.
        </p>
        <div className="flex gap-2 mt-1">
          <Link href="#try" className={`${buttonVariants({ variant: 'default', size: 'lg' })} min-w-[150px] shadow-sm`}>
            Try it out
          </Link>
          <Link
            href="https://github.com/JaleelB/shadcn-tag-input"
            className={`${buttonVariants({ variant: 'secondary', size: 'lg' })} shadow-sm`}
          >
            Github
          </Link>
        </div>
      </div>

      <div id="try" className="w-full py-8">
        <div className="w-full relative my-4 flex flex-col space-y-2">
          <div className="preview flex min-h-[350px] w-full justify-center p-10 items-center mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md border">
            <Form {...form}>
              <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 flex flex-col items-start">
                <FormField
                  control={form.control}
                  name="topics"
                  render={({ field }) => (
                    <FormItem className="flex flex-col items-start">
                      <FormLabel className="text-left">Topics</FormLabel>
                      <FormControl>
                        <TagInput
                          {...field}
                          placeholder="Enter a topic"
                          tags={tags}
                          className="sm:min-w-[450px]"
                          setTags={(newTags) => {
                            setTags(newTags);
                            setValue('topics', newTags as [Tag, ...Tag[]]);
                          }}
                        />
                      </FormControl>
                      <FormDescription>These are the topics that you&apos;re interested in.</FormDescription>
                      <FormMessage />
                    </FormItem>
                  )}
                />
                <Button type="submit">Submit</Button>
              </form>
            </Form>
          </div>
        </div>
      </div>
    </section>
  );
}

API Reference

TagInput

The primary component for user interaction. Configure the tag input behavior and appearance using these props, and manage tag data dynamically.

Props

type TagInputProps = {
  // Placeholder text for the input.
  placeholder?: string; // default: ""

  // Array of tags displayed as pre-selected.
  tags: Array<{ id: string; text: string }>; // default: []

  // Function to set the state of tags.
  setTags: React.Dispatch<React.SetStateAction<{ id: string; text: string }[]>>;

  // Enable or disable the autocomplete feature.
  enableAutocomplete?: boolean; // default: false

  // List of autocomplete options.
  autocompleteOptions?: Array<{ id: string; text: string }>; // default: []

  // Maximum number of tags allowed.
  maxTags?: number; // default: null

  // Minimum number of tags required.
  minTags?: number; // default: null

  // Make the input read-only.
  readOnly?: boolean; // default: false

  // Disable the input.
  disabled?: boolean; // default: false

  // Callback function when a tag is added.
  onTagAdd?: (tag: string) => void; // default: null

  // Callback function when a tag is removed.
  onTagRemove?: (tag: string) => void; // default: null

  // Allow duplicate tags.
  allowDuplicates?: boolean; // default: false

  // Maximum length of a tag.
  maxLength?: number; // default: null

  // Minimum length of a tag.
  minLength?: number; // default: null

  // Function to validate a tag.
  validateTag?: (tag: string) => boolean; // default: null

  // Character used to separate tags.
  delimiter?: Delimiter; // default: null

  // Show the count of tags.
  showCount?: boolean; // default: false

  // Placeholder text when tag limit is reached.
  placeholderWhenFull?: string; // default: ""

  // Sort tags alphabetically.
  sortTags?: boolean; // default: false

  // List of characters that can be used as delimiters.
  delimiterList?: string[]; // default: []

  // Truncate tag text to a certain length.
  truncate?: number; // default: null

  // Function to filter autocomplete options.
  autocompleteFilter?: (option: string) => boolean; // default: null

  // Layout direction of the tag inputs.
  direction?: 'row' | 'column'; // default: 'row'

  // A callback function that is called whenever the input value changes.
  onInputChange?: (value: string) => void; // default: null

  // A callback function that is used to render custom tag elements.
  customTagRenderer?: (tag: { id: string; text: string }) => React.ReactElement; // default: null

  // Function to be called when the input field gains focus.
  onFocus?: React.FocusEventHandler<HTMLInputElement>; // default: null

  // Function to be called when the input field loses focus.
  onBlur?: React.FocusEventHandler<HTMLInputElement>; // default: null

  // Only allow tags that are present in the autocomplete options.
  restrictTagsToAutocompleteOptions?: boolean; // default: false

  // A callback function to be called when a tag is clicked.
  onTagClick?: (tag: { id: string; text: string }) => void; // default: null

  // Enable drag and drop functionality.
  draggable?: boolean; // default: false

  // Position of the input field in relation to the tags.
  inputFieldPosition?: 'bottom' | 'top' | 'inline'; // default: 'bottom'

  // Show a button to clear all tags.
  clearAll?: boolean; // default: false

  // A callback function to be called when the clear all button is clicked.
  onClearAll?: () => void; // default: null

  // Additional props to be passed to the input field.
  inputProps?: React.InputHTMLAttributes<HTMLInputElement>; // default: {}

  // Use a popover to display tags instead of inline.
  usePopoverForTags?: boolean; // default: false
};

Delimiter

Define the delimiters that can be used to separate tags within the input.

enum Delimiter {
  Comma = ',',
  Enter = 'Enter',
}

Documentation

You can find out more about the API and implementation in the Documentation.

shadcn-tag-input's People

Contributors

aryanprince avatar garnerp avatar github-actions[bot] avatar jaleelb avatar maros-o avatar rohmanhm avatar wenwei-lin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

shadcn-tag-input's Issues

Autocomplete suggestions are muted and unclickable?

Tried using the autocomplete, this is from the props section.

image

<TagInput
      placeholder="Enter a topic"
      tags={autocompleteTags}
      enableAutocomplete
      restrictTagsToAutocompleteOptions
      autocompleteOptions={autoCompleteOptions}
      className="sm:min-w-[450px]"
      setTags={(newTags) => {
          setAutocompleteTags(newTags);
      }}
  />

Inline tags show horizontal in input

You recently implemented the inline tags (which look awesome), but it would be best, if there was an option to have the tags show horizontally in the input, like the image attached. Thanks :)

image

license info

hey,

awesome work - could you provide a license to the project?

Inline tags

Add the ability for the tags to appear in the input field, similar to the image attached below

image

UI issue with inline tags

I saw you recently implemented the inline tags, and when I tried to implement it in my app, I got this styling issue.
image

add npm i uuid

First I used this its awesome. second, you forgot to put npm i uuid in docs ... I got this error while using it

Inline tags - Remove tag when backspace key pressed

@JaleelB : One handy feature I can think of right now is if we press backspace in the input field that should have removed the last tag and so on, what do you say? May be one additional prop removeOnBackspace: boolean will do the trick.

Thank you!

React hook form

Please add the ability to use the register object directly with the input, so that we can validate them with React Hook form

Autocomplete feature not working properly

I've noticed that the autocomplete is not working properly. After the second character input, all the options disappear. I've been trying to debug this issue, but so far, I haven't had any luck in identifying the root cause.

Any guidance or suggestions would be greatly appreciated.

Despite this issue, I find the tool very useful and appreciate the effort put into developing it.
Thanks a lot.

Auto complete options

Feat: Prevent tags from being added if they are not in the autocomplete options or implement new functionality for this scenario

Tag Shapes Property - Rounded vs Pill

Summary

Hey, just wanted to point out that the pill shape buttons and rounded shape buttons in the UI components seem to be swapped. I could be totally wrong, but I thought I'd ask if that's what you intended. I'd like to make a PR for this if this was unintentional :)

Possible solution

In the shape property for the tag-input.tsx component, rounded could be rounded-lg and pill could be rounded-full, like the image I found online on the right:

image image

Current screenshots from demo website:

Rounded (for shadcn-tag-input):

image

Pill (for shadcn-tag-input):

image

Feature request: Autocomplete Overflow

Currently the autocomplete shows all existing tags, the list can become very long.

It would be perfect to use autocomplete in an overflow. Perhaps even in a popover so that other elements underneath are not moved too far.

Great work and many thanks

Draggable - UX suggestion

Hey!
First off, great contribution to OSS.

I have a minor feature that could be cool to implement for the draggable tags.
When dragging between each tag, it would increase the UX if there was some sort of visual cue (other than the dragging icon), indicating that they can be dragged.

An idea I have in mind is that when you drag a tag over another, the stationary tag moves out of the way, indicating that the dragged tag can be dropped. Maybe also add a slight bg-color to further visualize that it can be dropped there.

Example of the tag moving out of the way:
https://react-beautiful-dnd.netlify.app/iframe.html?id=board--simple

Kind regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.