Tagify

repository·master·Indexed 26 days ago

https://github.com/yaireo/tagify

A lightweight, high-performance tags input component that transforms HTML input or textarea elements into interactive tag interfaces. It supports Vanilla JS, React, Vue, and Angular. Key features include whitelist support (including Ajax-based dynamic loading), mixed-content mode, custom DOM templates, tag validation via Regex or custom functions, and integration with drag-and-drop libraries for tag reordering.

Tokens
9.7K
Snippets
25
Records
49
Agent score
87%

What's inside @yaireo/tagify

  1. Render tags in a single row with a scrollbar

    master

    By default, Tagify wraps tags to multiple lines. To force tags into a single horizontal row with a scrollbar, apply the following CSS to the .tagify selector:

    .tagify {
      flex-wrap: nowrap;
      overflow-x: auto;
      width: 100%;
      max-width: 500px;
      scrollbar-width: thin;
    }
  2. Integrate Tagify with React

    master

    Tagify provides a React wrapper that is dependency-light and JSX-free. Note that Tagify is not a controlled component.

    To use it, import the component from @yaireo/tagify/react and ensure you also import the Tagify CSS. If using SCSS, it is preferable to use @import with dart-sass.

    Important onChange behavior: The onChange event argument e includes a detail parameter. To access the original DOM input element, use e.detail.tagify.DOM.originalInput.

    import { useCallback, useRef } from 'react'
    import Tags from '@yaireo/tagify/react' // React-wrapper file
    import '@yaireo/tagify/dist/tagify.css' // Tagify CSS
    
    const App = () => {
        // on tag add/edit/remove
        const onChange = useCallback((e) => {
            console.log("CHANGED:"
                , e.detail.tagify.value // Array where each tag includes tagify's (needed) extra properties
                , e.detail.tagify.getCleanValue() // Same as above, without the extra properties
                , e.detail.value // a string representing the tags
            )
        }, [])
    
        return (
            <Tags
                whitelist={['item 1', 'another item', 'item 3']}
                placeholder='Add some tags'
                settings={{
                    blacklist: ["xxx"],
                    maxTags: 4,
                    dropdown: {
                        enabled: 0 // always show suggestions dropdown
                    }
                }}
                defaultValue="a,b,c" // initial value
                onChange={onChange}
            />
        )
    }
  3. Enable Mixed-Content mode

    master

    Mixed-content mode allows you to mix plain text with tags in a single input/textarea. To enable this, set mode: 'mix' and provide a pattern (Regex or String) that identifies the start of a tag.

    If the input contains text formatted with delimiters (e.g., [[tag]]), Tagify will attempt to convert them into tags if they exist in the whitelist. For mixed-content, it is recommended to use dropdown.position: 'text' to ensure the suggestions list appears near the cursor.

    {
      //  mixTagsInterpolator: ["{{", "}}"],  // optional: interpolation before & after string
      mode: 'mix',    // <--  Enable mixed-content
      pattern: /@|#/  // <-- Text starting with @ or #
    }
  4. Save Tagify state to a server

    master

    In framework-less projects, you should listen for the change event on the original input/textarea element to capture when the Tagify state has been updated. This allows you to sync the component's value with your backend.

    var tagify = new Tagify(...)
    
    // Listen to "change" events on the "original" input/textarea element
    tagify.DOM.originalInput.addEventListener('change', onTagsChange)
    
    async function onTagsChange(e){
      const {name, value} = e.target
      // Call your server-side save function
      await saveToServer(name, value)
    }
  5. Enable Drag & Sort for tags

    master

    To allow users to reorder tags by dragging, integrate a 3rd-party drag-and-drop library (such as @yaireo/dragsort). You must bind the library to the Tagify main element and call tagify.updateValueByDOMTags() when the drag operation ends to sync the Tagify value with the new DOM order.

    var tagify = new Tagify(inputElement)
    
    // bind "DragSort" to Tagify's main element and tell
    // it that all the items with the below "selector" are "draggable"
    var dragsort = new DragSort(tagify.DOM.scope, {
        selector: '.'+tagify.settings.classNames.tag,
        callbacks: {
            dragEnd: onDragEnd
        }
    })
    
    // must update Tagify's value according to the re-ordered nodes in the DOM
    function onDragEnd(elm){
        tagify.updateValueByDOMTags()
    }
  6. Persist whitelist and value data using localStorage

    master

    To prevent pre-filled values from being removed when enforceWhitelist is true (e.g., when the whitelist loads asynchronously), you can persist the whitelist and value data to localStorage. This is achieved by providing a unique id to the Tagify instance.

    var input = document.querySelector('input'),
        tagify = new Tagify(input, {
          id: 'test1',  // must be unique (per-tagify instance)
          enforceWhitelist: true,
        }),
  7. Install Tagify via CDN

    master

    To use Tagify via CDN, include the following script and stylesheet in your HTML before any other code that uses Tagify. Tagify will then be available globally.

    To load a specific version, use the @ syntax (e.g., unpkg.com/@yaireo/tagify@3.1.0).

    Important: You must include the tagify.css file for the component to render correctly.

    <script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify"></script>
    <link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet" type="text/css" />
  8. Implement an Ajax whitelist

    master

    To load suggestions dynamically from a server as the user types, use the tagify.loading(boolean) method to control the loading animation and update the tagify.whitelist property with the fetched data. It is recommended to use an AbortController to cancel previous requests when new input is received.

    var input = document.querySelector('input'),
        tagify = new Tagify(input, {whitelist:[]}),
        controller;
    
    tagify.on('input', onInput)
    
    function onInput( e ){ 
      var value = e.detail.value
      tagify.whitelist = null 
    
      controller && controller.abort()
      controller = new AbortController()
    
      tagify.loading(true)
    
      fetch('http://get_suggestions.com?value=' + value, {signal:controller.signal})
        .then(RES => RES.json())
        .then(function(newWhitelist){
          tagify.whitelist = newWhitelist
          tagify.loading(false).dropdown.show(value)
        })
    }
  9. Edit tags

    master

    Tags can be edited by double-clicking them (default) or by setting editTags: 1 to enable single-click editing. Changes are saved on blur or by pressing Enter. Pressing Escape reverts the change. Ctrl+Z reverts changes if an edited tag becomes invalid (e.g., duplicate or blacklisted).

    To disable editing for all tags, set editTags: false or null. To disable editing for specific tags, set the editable: false property in the tag's data object.

    <input value='[{"value":"foo", "editable":false}, {"value":"bar"}]'>
  10. Use aliases and custom search keys in suggestions

    master

    To improve searchability in the suggestions list:

    1. Aliases: Add a searchBy property to whitelist objects. Tagify will match typed text against this property.
    2. Custom Search Keys: Use dropdown.searchKeys to allow fuzzy-searching across multiple properties of a whitelist object (e.g., searching by nickname or email instead of just value).
    // Example whitelist with searchBy alias
    whitelist = [
        { value:'Israel', code:'IL', searchBy:'holy land, desert, middle east' },
        ...
    ]
    
    // Example configuration to search multiple keys
    {
      dropdown: {
        searchKeys: ["nickname", "email"]
      }
    }
  11. Modify the original input value format

    master

    By default, Tagify syncs the original input's value as a JSON string (e.g., '[{"value":"cat"}]'). If you prefer a different format, such as a comma-separated string, use the originalInputValueFormat setting.

    Note: It is recommended to keep the default JSON format if your tags might contain commas (e.g., addresses).

    var tagify = new Tagify(inputElm, {
      originalInputValueFormat: valuesArr => valuesArr.map(item => item.value).join(',')
    })