You misinterpreted the meaning of these two tags, namely <h:link> and <h:commandLink> , so you also misinterpreted the value of <f:param> attached to either of the two. In any case, you should always read the documentation before asking questions in order to get more information.
<h:link> displays the HTML anchor "a". The component value is displayed as anchor text, and the component result is used to determine the destination URL displayed in the "href" attribute. Any UIParameter child components UIParameter added to the string, which will be displayed as the value of the "href" attribute as request parameters before rendering ...
<h:commandLink> displays the HTML anchor "a", which acts as a submit button * when clicked ... if the disabled attribute is missing or its value is false. It displays "#" as the value of the href attribute, displays the current value of the component as link text, if one is specified, and * displays JavaScript that is functionally equivalent to the following as the value of the onclick attribute:
document.forms['CLIENT_ID']['hiddenFieldName'].value='CLIENT_ID'; document.forms['CLIENT_ID']['PARAM1_NAME'].value='PARAM1_VALUE'; document.forms['CLIENT_ID']['PARAM2_NAME'].value='PARAM2_VALUE'; return false; document.forms['CLIENT_ID'].submit()"
where hiddenFieldName is as described above, CLIENT_ID is the clientId of the UICommand component, PARAM_NAME and PARAM_VALUE are the names and values, respectively, of any nested child elements of the UIParameter.
In other words, in the <h:link> tag, the nested <f:param> appears as the request parameter of the generated URL, while the <h:commandLink> nested <f:param> appears as the request parameter with the specified value.
While the first one is clear, the second deserves a better development. To understand what he is doing, <h:commandLink> that if you ignore the details, then <h:commandLink> sends a POST request and <h:commandLink> all the nested <f:param> tags as request parameters. But it is up to you how you deal with them, since navigation is entirely in your hands .
So, the first option is to set the hard-coded action attribute , which the case uses, is doubtful , for example, in action="second-page" , and how you did not pass any request parameter at all . What will be done is POSTing on the same presentation and forwarding to the second without taking any action. Pretty stupid action.
The second option is to specify an action method, for example, in action="#{bean.action}" . In this case, you should handle the navigation according to the provided action method , i.e. Return null / void from the postback method or return the result of the navigation action as a string to make the specified appearance. As for the request parameters that you passed using <f:param> , they will be available with standard JSF tools , for example @ManagedProperty("#{param.name}") on the bean with the request, or by calling ExternalContext#getRequestParameterMap() in any case, bean, for example, in an action method, for example, in String param = externalContext.getRequestParameterMap().get("name") . So, now you have your own parameter in the action method, which you can use as you like, just stick to the set of rules that exist for URLs.
Two things worth mentioning. Remember that request parameters passed with a command line call will be available only inside the same request, since you can expect it to withstand faces-redirect=true , which basically launches another request. Another option is to specify includeviewparams=true to pass the parameters of the current view, if necessary, as indicated in another answer.