docusaurus icon indicating copy to clipboard operation
docusaurus copied to clipboard

Allow CSS to target layout of a single page (for docs, blog, pages)

Open armano2 opened this issue 3 years ago • 8 comments

Have you read the Contributing Guidelines on issues?

Description

I went trough documentation and i'm unable to find an option to disable stickiness of navbar for specific page/s

this refers to class .navbar--fixed-top

as an example of page that i'd like to disable stickiness is a typescript-eslint playground

image

image


i'm not sure if this is a documentation request or feature request

Self-service

  • [ ] I'd be willing to address this documentation request myself.

armano2 avatar Jun 10 '22 00:06 armano2

Let's say it's a feature request. What you want is for some CSS to only apply to one page—this should be achievable if we have a class name that's unique for every route. https://github.com/facebook/docusaurus/pull/6933 already did some work on this, but not enough: the class name is still not granular enough.

Josh-Cena avatar Jun 10 '22 01:06 Josh-Cena

Couldn't this work?

https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/website/src/pages/play.tsx

function Play(): JSX.Element {
  return (
    <HtmlClassNameProvider className="my-custom-playground-className">
      <Layout title="Playground" description="Playground" noFooter={true}>
        <BrowserOnly fallback={<Loader />}>
          {(): JSX.Element => {
            const Playground = lazy(() => import("../components/Playground"));
            return (
              <Suspense fallback={<Loader />}>
                <Playground />
              </Suspense>
            );
          }}
        </BrowserOnly>
      </Layout>
    </HtmlClassNameProvider>
  );
}

This API is not officially documented for now, hopefully we may remove it in the future.

Its only role is to allow composition on avoid Helmet <Head> component for <html className="xyz">. (ie a children HTML className does not override parent ones)

export function HtmlClassNameProvider({
  className: classNameProp,
  children
}: {
  className: string,
  children: ReactNode
}): JSX.Element {
  const classNameContext = React.useContext(HtmlClassNameContext);
  const className = clsx(classNameContext, classNameProp);
  return (
    <HtmlClassNameContext.Provider value={className}>
      <Head>
        <html className={className} />
      </Head>
      {children}
    </HtmlClassNameContext.Provider>
  );
}

If you don't need composition on the playground page, you could as well just use this, which is already part of our public API:

<Head>
  <html className={className} />
</Head>

slorber avatar Jun 15 '22 13:06 slorber

@slorber yes your solution is working, but at the end i decided to do it differently, by changing how tooltips are rendered in playground

armano2 avatar Jun 16 '22 11:06 armano2

👍

So I'll close this issue for now

slorber avatar Jun 16 '22 11:06 slorber

This is a good solution for React pages, but not for Markdown pages where you don't have access to the wrapping component. In the long term I think we should have a route-specific class name for each page.

Josh-Cena avatar Jun 16 '22 11:06 Josh-Cena

This is a good solution for React pages, but not for Markdown pages where you don't have access to the wrapping component. In the long term I think we should have a route-specific class name for each page.

We have doc id/version for each md doc.

And it looks like frontmatter wrapperClassName is wired to HTML className already for md pages. (which looks suspicious because the same prop name is applied to different dom tree levels for docs/pages...)

I think only blog posts do not easily allow to be targeted with granularity.

slorber avatar Jun 16 '22 11:06 slorber

Ah yes, forgot about that. Correct, only blog posts can't be differentiated

Josh-Cena avatar Jun 16 '22 11:06 Josh-Cena

I think we can re-open and do this:

  • md page frontMatter.wrapperClassName => apply to Layout wrapperClassName (instead of html, for consistency with DocPage)
  • md page frontMatter.htmlClassName (new)
  • blog => find a way to generate a unique html className per post

There are other cases (like category index...), but I doubt they would be as useful as docs/blog/pages

slorber avatar Jun 16 '22 11:06 slorber

@slorber Hi Slorber, I'm running into this exact issue, where I want a way to target styling to a specific doc file.

I see above, you talk about md.page frontMatter.wrapperClassName or htmlClassName. If I understand correctly, with these, I'd be able to globally target the provided wrapperClassName and htmlClassName and custom style a Markdown page.

Have these been added yet?

Michaelsulistio avatar Apr 21 '23 05:04 Michaelsulistio

@Michaelsulistio yes, give it a try and see what elements in the DOM permits you to target that specific page.

where I want a way to target styling to a specific doc file.

If it's a doc page (ie of the docs plugin) we already add many metadata at the top to help you target it individually

For example, this page: https://docusaurus.io/docs/configuration has the following html classname:

<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-2.4.0 docs-doc-page docs-doc-id-configuration">

This should be largely enough to target it.

If you want more help, please provide a concrete example in a repro with the page you want to target and I can tell you how to do so.


This issue remain open because there are still some things that you can't target easily (like blog posts). See https://github.com/facebook/docusaurus/issues/7592#issuecomment-1157553912)

But most of it has been implemented already, and you should be able to achieve what you want here.

slorber avatar Apr 21 '23 10:04 slorber

does the @docusaurus/Head method work if the goal is to include a separate processed /src/css/custom2.css only on a specific /src/pages/foo.mdx page?

nektro avatar Sep 18 '23 05:09 nektro

does the @docusaurus/Head method work if the goal is to include a separate processed /src/css/custom2.css only on a specific /src/pages/foo.mdx page?

<Head> works the way it's documented (https://github.com/staylor/react-helmet-async) anywhere JSX works, including MDX (which is compiled to JSX in the end). "works" is ambiguous so if you read the doc and it doesn't work as documented, you should open an issue to the package repo directly.

slorber avatar Sep 18 '23 17:09 slorber