Changing the form template to include hidden input widgets is a decent way to do the job, but there's another way to accomplish the same goal by using the generic form templates and schema fields.  This approach could be better in some circumstances.

To make a hidden input, i.e. <input type="hidden" .../>, we can derive a new widget from the existing formlib.widget.SimpleInputWidget, which as a hidden() method that renders the field as a hidden input element.  We can then derive a new schema field from the existing zope.schema.Text or zope.schema.TextLine field types.  We can then tie the new schema type to the widget by defining an adapter.

#_____________________________________________________________________________________________
#  The code below defines a new HiddenText schema field type and associates a widget
# with it that renders as a hidden input type.
#  A HiddenText schema field may be used to persist state in forms between the server
# and the browser.
import grok
from zope.schema import TextLine
from zope.publisher.browser import IBrowserRequest
from zope.formlib.interfaces import IInputWidget
from zope.formlib.widget import SimpleInputWidget

#________________________________________________________________
class HiddenText(TextLine):
    ''' We register an adapter for this new schema field which renders a hidden text field '''

#________________________________________________________________
class HiddenTextWidget(SimpleInputWidget):
    ''' Our hidden text widget is easily derived from SimpleInputWidget.  We override
        the __call__ to render as a hidden input
    '''
    def _toFieldValue(self, aInput):
        return unicode(aInput)

    def __call__(self):
        return self.hidden()

#________________________________________________________________
class HiddenTextAdapter(grok.MultiAdapter):
    '''  Define an adapter for our schema field which selects our hidden text widget
    '''
    grok.adapts(HiddenText, IBrowserRequest)
    grok.implements(IInputWidget)

    def __new__(cls, field, request):
        return HiddenTextWidget(field, request)

To use this schema field type in a form, remember to set the title as an empty string and the required argument to False:

from hiddentext import HiddenText

class mySchema(Interface):
    hidden = HiddenText(title=u"", description=u"", required=False)
    ...

class myModel(grok.Model):
    grok.implements(mySchema)
    hidden = "My persisted data"

class myForm(grok.Form):
    grok.context(myModel)
    ....

That's as easy as it gets.

One of the amazing things about Grok and other frameworks that use the ZCA is the ease with which new behaviour may be implemented, or existing behaviour redefined.

Grok 4 Noobs

Another way of rendering hidden input widgets