Home » Reactjs » How to generate unique IDs for form labels in React?

How to generate unique IDs for form labels in React?

Posted by: admin November 30, 2017 Leave a comment

Questions:

I have form elements with labels and I want to have unique IDs to link labels to elements with htmlFor attribute. Something like this:

React.createClass({
    render() {
        const id = ???;
        return (
            <label htmlFor={id}>My label</label>
            <input id={id} type="text"/>
        );
    }
});

I used to generate IDs based on this._rootNodeID but it’s unavailable since React 0.13. What is the best and/or simplest way to do it now?

Answers:

This solutions works fine for me.

utils/newid.js:

let lastId = 0;

export default function(prefix='id') {
    lastId++;
    return `${prefix}${lastId}`;
}

And I can use it like this:

import newId from '../utils/newid';

React.createClass({
    componentWillMount() {
        this.id = newId();
    },
    render() {
        return (
            <label htmlFor={this.id}>My label</label>
            <input id={this.id} type="text"/>
        );
    }
});

But it won’t work in isomorphic apps.

Added 17.08.2015. Instead of custom newId function you can use uniqueId from lodash.

Updated 28.01.2016. It’s better to generate ID in componentWillMount.

Questions:
Answers:

The id should be placed inside of componentWillMount, not render. Putting it in render will re-generate new ids unnecessarily.

If you’re using underscore or lodash, there is a uniqueId function, so your resulting code should be something like:

componentWillMount() {
    const id = _.uniqueId("prefix-");
    this.setState({id: id});
}

render() { 
  const id = this.state.id;
  return (
    <div>
        <input id={id} type="checkbox" />
        <label htmlFor={id}>label</label>
    </div>
  );
}

Questions:
Answers:

There are a lot of “duct tape” solutions.
One is https://github.com/DelvarWorld/Unique-Id-Mixin

Questions:
Answers:

I prefer to just let react auto generate the id’s for me. I’m not entirely sure if this is correct use since underscore is usually private but it does the trick.

this._reactInternalInstance._rootNodeID

render () {
  <button 
    id={this._reactInternalInstance._rootNodeID}>
    {this.props.children}
    {/*tooltip */}
    <div 
      htmlFor={this._reactInternalInstance._rootNodeID}
      className="mdl-tooltip mdl-tooltip--large">
      {this.props.children}
    </div>
  </button>
}

Here is an example of using React to auto generate the ID’s for the components so that MDL ( Material Design Lite ) can target the parent for their tooltip components

React MDL Tooltip Example

Questions:
Answers:

Hopefully this is helpful to anyone coming looking for a universal/isomorphic solution, since the checksum issue is what led me here in the first place.

As said above, I’ve created a simple utility to sequentially create a new id. Since the IDs keep incrementing on the server, and start over from 0 in the client, I decided to reset the increment each the SSR starts.

// utility to generate ids
let current = 0

export default function generateId (prefix) {
  return `${prefix || 'id'}-${current++}`
}

export function resetIdCounter () { current = 0 }

And then in the root component’s constructor or componentWillMount, call the reset. This essentially resets the JS scope for the server in each server render. In the client it doesn’t (and shouldn’t) have any effect.

Questions:
Answers:

You could use a library such as node-uuid for this to make sure you get unique ids.

Install using:

npm install node-uuid –save

Then in your react component add the following:

import {default as UUID} from "node-uuid";
import {default as React} from "react";

export default class MyComponent extends React.Component {   
  componentWillMount() {
    this.id = UUID.v4();
  }, 
  render() {
    return (
      <div>
        <label htmlFor={this.id}>My label</label>
        <input id={this.id} type="text"/>
      </div>
    );
  }   
}

Questions:
Answers:

You can use id${new Date().getTime()} since new Date().getTime() returns the number of milliseconds since 1970/01/01 and works fine as a unique id.

The following Checkbox functional component creates an unique id used in the label and in the input checkbox for each render, so it’s ok to move it to componentWillMount.

const CheckboxComponent = (props: Props) => {

    const uniqueId = `id${new Date().getTime()}`;

    return (
        <label
            htmlFor={uniqueId}
            style={[styles.container]}
        >
            <input
                id={uniqueId}
                type="checkbox"
                style={[styles.spacer]}
                {...rest}
            />
            {props.label && (
                <span style={[styles.label]}>{props.label}</span>
            )}
        </label>
    );
};
const styles = {
    label: {
        color: "#333",
    },
    container: {
        display: "flex",
        flexDirection: "row",
    },
    spacer: {
        flex: 1,
    },
};