Yes I suppose it's not a good idea to have the same ID, but unless you use script code that references the radio buttons that's not going to matter.
I made a change to the behavior of the helper: If you specify an id in the lcAttributes that value is used instead of the name. So you can now do:
HtmlRadioButton("radColor","Blue",true,"blue",[ class="radiocolor" id="radColor_1"])
HtmlRadioButton("radColor","Red",false,"red",[ class="radiocolor" id="radColor_2"])
HtmlRadioButton("radColor","Green",false,"red",[ class="radiocolor" id="radColor_3"])
With the HTMLRadioButton control as it's currently implemented, the name parameter gets assigned to both the name and id attributes. But if you want the buttons to work as a group, don't all of them have to have the same name? Which means you end up with non-unique id's on the same page, which is invalid HTML.
I came up with a variation that I find to be a lot more useful. Code is posted below FWIW...
FUNCTION HTMLRadioGroup(lcName,lcPrompts,lnCount,lnChecked,lcValues,lcAttributes,lcLabelAttr,lcPreWrap,lcPostWrap,lcDelim)
LOCAL lcChecked, lcID, lcOutput, lcPrompt, lcValue, llChecked, llForced, i
IF EMPTY(lcName)
lcName = ""
ENDIF
IF EMPTY(lcPrompts)
lcPrompts = ""
ENDIF
IF EMPTY(lcDelim)
lcDelim = [;]
ENDIF
IF EMPTY(lnCount)
lnCount = OCCURS(lcDelim,lcPrompts)
ENDIF
IF EMPTY(lcValues)
lcValues = lcPrompts
ENDIF
llForced = .F.
IF VARTYPE(lnChecked) = "C"
llForced = ATC(":FORCED",lnChecked) > 0
IF llForced
lnChecked = STRTRAN(lnChecked,":FORCED","",1,-1,1)
ENDIF
IF lnChecked = "="
lnChecked = EVAL(SUBSTR(lnChecked,2))
ELSE
lnChecked = VAL(lnChecked)
ENDIF
ELSE
IF VARTYPE(lnChecked) <> "N"
lnChecked = 0
ENDIF
ENDIF
IF VARTYPE(lcAttributes) = [C]
lcAttributes = [ ] + lcAttributes
ELSE
lcAttributes = []
ENDIF
IF VARTYPE(lcLabelAttr) = [C]
lcLabelAttr = [ ] + lcLabelAttr
ELSE
lcLabelAttr = []
ENDIF
IF EMPTY(lcPreWrap)
lcPreWrap = []
ENDIF
IF EMPTY(lcPostWrap)
lcPostWrap = []
ENDIF
lcOutput = []
FOR i = 1 TO lnCount
lcPrompt = GETWORDNUM(lcPrompts,i,lcDelim)
lcValue = GETWORDNUM(lcValues,i,lcDelim)
lcID = lcName + TRANSFORM(i)
IF VARTYPE(REQUEST) = "O" AND Request.IsFormVar(lcName) AND !llForced
llChecked = (lcValue == Request.Form(lcName))
ELSE
llChecked = (i = lnChecked)
ENDIF
lcChecked = IIF(llChecked,[ checked="checked"],[])
lcOutput = lcOutput + ;
lcPreWrap + [<input type="radio" id="] + lcID + [" name="] + lcName + [" value="] + lcValue + ["] + lcChecked + lcAttributes + [/>] +;
[<label for="] + lcID + ["] + lcLabelAttr + [>] + lcPrompt + [</label> ] + lcPostWrap + CRLF
ENDFOR
RETURN lcOutput
ENDFUNC