Q:

CSS label:before with content styling not working unless id provided for elements

I have built a clickable am / pm button that is part of a time selector. It will be sitting inside a dynamic table (html table where the user can click a button to add rows to the table). Since it is in a dynamic table, I will be generating the elements and won't have much use of element id's when trying to access them in javascript (as I won't know them individually).
With the below clickable label, is there any way to achieve the same result without assigning an id to the checkbox?

.text_toggle
{
    display: none;
}

.text_toggle + label
{
    position: relative;
    cursor: pointer;
    color: #aaa;
}

.text_toggle + label:hover
{
    color: blue;
}

.text_toggle:not(:checked) + label:before
{
    content: attr(data-off);
    position: absolute;
}

.text_toggle:checked + label:before
{
    content: attr(data-on);
    position: absolute;
}
<input id="am_pm" class="text_toggle" type="checkbox" checked>
                <label for="am_pm" data-off="am" data-on="pm"></label>

A:

Yes, you can make a label and put your checkbox inside it, then you add another element with your custom attributes.

.switch{
/* other styles here */
}
.switch > input[type=checkbox]{
display:none;
}

.switch input[type=checkbox] + span::before{
  content: attr(data-off)
}
.switch input[type=checkbox]:checked + span::before{
content: attr(data-on)
}
<label class="switch">
<input type="checkbox" />
<span data-off="Off" data-on="On"></span> <!-- I made it with span, but feel free to use any other tag -->
</label>

