Most tapestry components take the approach of using the "id" parameter (not to be confused with t:id) if one is provided. If an "id" is not provided, a clientId is generated which is guaranteed not to clash with other id's on the page.
public class MyComponent implements ClientElement { @Environmental private JavaScriptSupport jss; @Parameter(name = "id", defaultPrefix = BindingConstants.LITERAL) private String idParameter; @Inject private ComponentResources resources; void beginRender(MarkupWriter writer) { clientId = resources.isBound("id") ? idParameter : jss.allocateClientId(resources); writer.element("div", "id", clientId); ... } @Override public String getClientId() { return clientId; } }