react-helmet icon indicating copy to clipboard operation
react-helmet copied to clipboard

More complex title templates

Open mxstbr opened this issue 7 years ago • 12 comments

Feature request

In my application I have a top-level Helmet component which renders the default title, twitter and open graph meta tags. I have pages, each of which renders a Helmet component with some custom text, and I have a global Navbar which has the state of the unread notifications which I want to display in the title.

Essentially, I want my title to look like this: (1) Subpage | MyApp.

The issue is that the title template doesn't allow me to have custom titles from the pages and also the unread notification count, so it'd show either Subpage | MyApp or (1) | MyApp, but I can't have both :cry:

Is there a way we could adapt the API to make more complex title theming possible? Would be happy to submit a PR if I get some pointers, or maybe I am missing some existing feature that makes this possible?

mxstbr avatar Jun 16 '17 13:06 mxstbr

This would be pretty useful. Maybe it would help if nested <title> can be combined in a way other than last-write-wins. First thought is to allow function child inside the tags.

For example.

<div>
  <Helmet>
    <title>MyApp</title>
  </Helmet>
  <Helmet>
    <title>{prev => `Subpage | ${prev}`}</title>
  </Helmet>
  <Helmet>
    <title>{prev => `(0) ${prev}`}</title>
  </Helmet>
</div>

Then you can convert those into ordered list of title creators.

const titles = [
  () => `MyApp`,
  prev => `Subpage | ${prev}`,
  prev => `(0) | ${prev}`
]

Which can be reduced down to a value.

titles.reduce((acc, f) => f(acc), '')

Note: If the last <title> is a string s, then it would exhibit the current behaviour of last-write-wins, since the last function reduced over is() => s.

jaysoo avatar Jun 22 '17 03:06 jaysoo

I like that! Would definitely solve my problem.

mxstbr avatar Jun 22 '17 13:06 mxstbr

Interested in knowing what @cwelch5 thinks -- I'm not married to this idea. Seems to be some overlap with titleTemplate, such as..

<div>
  <Helmet titleTemplate="%s | MyApp" />
  <Helmet>
    <title>Subpage</title>
  </Helmet>
</div>

Being roughly equivalent to:

<div>
  <Helmet>
    <title>MyApp</title>
  </Helmet>
  <Helmet>
    <title>{prev => `Subpage | ${prev}`}</title>
  </Helmet>
</div>

However, use cases like overriding titleTemplate is not possible with functional <title>.

More realistic scenario would be to use a function as the last <title> rendered.

<div>
  <Helmet titleTemplate="%s | MyApp" defaultTitle="MyApp" />
  <Helmet>
    <title>Subpage</title>
  </Helmet>
  <Helmet>
    <title>{prev => `(0) ${prev}`}</title>
  </Helmet>
</div>

jaysoo avatar Jun 22 '17 14:06 jaysoo

Would be really interested in this as well, my use case is slightly simpler (I would like nested titleTemplate so my page title can be "Nested | Child | MainTitle") which comes from something like :

<div>
  <Helmet titleTemplate="%s | MainTitle"` defaultTitle="MainTitle" />
  <child>
    <Helmet titleTemplate="%s | Child" defaultTitle="Child" />
    <nested>
      <Helmet title="Nested" />
    </nested>
  </child>
</div>

jduthon avatar Sep 26 '17 09:09 jduthon

It would be really useful to have the nested capabilities like @jduthon said

bogdansoare avatar Oct 09 '17 11:10 bogdansoare

can you add method title.toInnerText() or title.toComponent("%s | MyApp")?

luongthanhlam avatar Oct 17 '17 04:10 luongthanhlam

Any progress on this?

I have exactly the same use case as @mxstbr, wanting to add unread notifications to my title!

Neglexis avatar Nov 20 '17 14:11 Neglexis

@mxstbr @jaysoo Hey, I just published a tiny library react-titled that supports more complex nesting. It uses the new context API that comes with React 16.3.

You can use it as

import { Titled } from 'react-titled';

<Titled title={() => 'Example.com'}>
  <h1>Welcome!</h1>
  <Titled title={title => `Homepage | ${title}`} />
</Titled>;

outputs

Homepage | Example.com

Hope you find it useful. :)

react-helmet is still really great for other <head> tags where composing is not needed. I think it doesn't make sense to dramatically change react-helmet's API to support that so I've create a new lib.

tajo avatar Apr 08 '18 22:04 tajo

I'm assuming nothing like this ever got implemented? I have the exact same use case as others, wanting to put Unread Notifications in the title.

bslinger avatar Nov 14 '19 05:11 bslinger

I've opened a PR for this here https://github.com/nfl/react-helmet/pull/541

My proposal works as follows:

https://github.com/nfl/react-helmet/blob/067a35c667e868cf2c49c390bd6ac7c429497b37/test/HelmetTest.js#L271-L280

=> Page Name | Section Name | Site Name

https://github.com/nfl/react-helmet/blob/067a35c667e868cf2c49c390bd6ac7c429497b37/test/HelmetTest.js#L297-L312

=> (1) Page Name | Section Name | Site Name

penx avatar Apr 22 '20 16:04 penx

I'm still thinking if there's a clearer API/variable naming, but I think:

  • for the template A%sB the API should allow insertion in to 4 points - 1A2%s3B4
  • the API should not be a breaking change, so when titleTemplate is a string it should override any previous nesting

penx avatar Apr 22 '20 21:04 penx

Do you know if there is a 2020 solution for this kind of issues? using or not using Helmet??

Ethaan avatar Aug 29 '20 04:08 Ethaan