Table of Contents
Link and list styling
Combining a few of our components and CSS classes you can create a responsive and accessible table of contents.
Style links without underline (until hovered or focused) with the
.bf-title-link class.
<a class="bf-title-link" href="#heading_id">Link to Heading</a>
Style the <ol> list as a TOC with the .bf-toc class.
<ol class="bf-toc"> <li><a class="bf-title-link" href="#heading_id">Link to Heading</a></li> </ol>
Nested lists will inherit the TOC styling. Combined with links it will look something like this:
Scroll to a page section
Native HTML anchors allow you to link to a page section.
<a href="#my-heading">This link will scroll to</a> <h3 id="my-heading">The element with matching `id`</h3>
Highlight active heading
Optionally wrap the content in an element with .bf-hightlight-target to
highlight the currently active header.
<article class="bf-highlight-target"> <a href="#my-heading">This link will scroll to</a> <h3 id="my-heading">The element with matching `id`</h3> </article>
Responsive components
Depending on the width required for your page content, you can probably placed the table of contents on the right hand side in a sticky container, replaced by an accordion for small screens.
1. Sticky box for desktop
We provide a <Sticky> component to create a box that follows
scrollable content, then sticks to the top.
<Sticky> <ol className="bf-toc">...</ol> </Sticky>
2. Accordion for mobile
For mobile screens, we don't have sufficient space for the sticky box, instead
we can use a full-width <Accordion> preceding the content.
<Accordion> <Accordion.Item title="On this page"> <ol className="bf-toc">...</ol> </Accordion.Item> </Accordion>
3. Breakpoint CSS
Since we don't want to show all of these elements for all screens, we can use some breakpoint classes.
.to-mediumfor mobile-only elements; the accordion.from-mediumon desktop-only elements; the sticky box
The medium keyword breaks at 960px viewport width.
4. All of the above
Here we've also added an "On this page" header in the sticky box.
const toc = ( <ol className='bf-toc'> <li> <a className="bf-title-link">Link</a> </li> {/* more items... */} </ol> ); // placed in a right-hand column layout <Sticky className='from-medium'> <header className='bfc-base-2 bf-medium bf-strong'>On this Page</header> {toc} </Sticky> // placed preceding content <Accordion className="to-medium"> <Accordion.Item title="On this page">{toc}</Accordion.Item> </Accordion>
Live demo
Try resizing the preview pane to see mobile/desktop version, or open in codesanbox.io and resize window.
import { useState } from "react"; import { faList } from "@fortawesome/free-regular-svg-icons"; import Sticky from "@intility/bifrost-react/Sticky"; import Accordion from "@intility/bifrost-react/Accordion"; import Button from "@intility/bifrost-react/Button"; import Icon from "@intility/bifrost-react/Icon"; export default function TocDemo() { const toc = ( <ol className="bf-toc"> <li> <a href="#scrolldown" className="bf-title-link"> Scroll downwards </a> </li> <li> <a href="#secondSection" className="bf-title-link"> Second section </a> <ol> <li> <a href="#firstSubSection" className="bf-title-link"> First sub-section </a> </li> <li> <a href="#secondSubSection" className="bf-title-link"> Second sub-section </a> </li> </ol> </li> <li> <a href="#scrollup" className="bf-title-link"> Scroll upwards </a> </li> </ol> ); return ( <> <div className="bf-content bf-highlight-target"> <h1> <span className="from-medium">Desktop demo</span> <span className="to-medium">Mobile demo</span> </h1> <p> On desktop screens over 960px you should get a sticky box, but on smaller screens a floating button instead, which opens a drawer from bottom. </p> <p> Resize your browser window to test{" "} <span className="from-medium">mobile</span> <span className="to-medium">desktop</span> mode. </p> <Accordion className="to-medium"> <Accordion.Item title="On this page">{toc}</Accordion.Item> </Accordion> <div className="toc-demo-layout"> <Sticky className="from-medium bfl-grid"> <header className="bfc-base-2 bf-medium bf-strong"> On this Page </header> {toc} </Sticky> <div> <h2 id="scrolldown">Scroll downwards</h2> <p> Lorem ipsum dolor sit amet. Eos Quis laudantium 33 consequatur dicta eum expedita dolore aut nostrum nihil. Est dolorem consequuntur et accusamus fuga et repellendus facilis et incidunt explicabo. 33 galisum sapiente non provident itaque et itaque dolores non maiores doloribus a suscipit eveniet! 33 illum labore id veniam sint cum deserunt omnis est deserunt facere et eaque exercitationem et pariatur velit? </p> <p> Qui minima doloribus ut dolore iure qui debitis voluptatibus aut dolore nostrum hic consequatur. Sed consequatur nemo qui ipsum enim et velit architecto sit perferendis repellendus. </p> <p> Sed deserunt voluptatum et voluptate voluptatem aut labore reprehenderit vel corporis sapiente. 33 omnis magnam et ratione saepe aut dicta veritatis rem voluptatem necessitatibus aut voluptates autem est sunt delectus aut commodi doloribus. </p> <p> Lorem ipsum dolor sit amet. Eos Quis laudantium 33 consequatur dicta eum expedita dolore aut nostrum nihil. Est dolorem consequuntur et accusamus fuga et repellendus facilis et incidunt explicabo. 33 galisum sapiente non provident itaque et itaque dolores non maiores doloribus a suscipit eveniet! 33 illum labore id veniam sint cum deserunt omnis est deserunt facere et eaque exercitationem et pariatur velit? </p> <h2 id="secondSection">Second section</h2> <p> Lorem ipsum dolor sit amet. Eos Quis laudantium 33 consequatur dicta eum expedita dolore aut nostrum nihil. Est dolorem consequuntur et accusamus fuga et repellendus facilis et incidunt explicabo. 33 galisum sapiente non provident itaque et itaque dolores non maiores doloribus a suscipit eveniet! 33 illum labore id veniam sint cum deserunt omnis est deserunt facere et eaque exercitationem et pariatur velit? </p> <h3 id="firstSubSection">First sub-section</h3> <p> Sed deserunt voluptatum et voluptate voluptatem aut labore reprehenderit vel corporis sapiente. 33 omnis magnam et ratione saepe aut dicta veritatis rem voluptatem necessitatibus aut voluptates autem est sunt delectus aut commodi doloribus. </p> <h3 id="secondSubSection">Second sub-section</h3> <p> Sed deserunt voluptatum et voluptate voluptatem aut labore reprehenderit vel corporis sapiente. 33 omnis magnam et ratione saepe aut dicta veritatis rem voluptatem necessitatibus aut voluptates autem est sunt delectus aut commodi doloribus. </p> <h2 id="scrollup">Scroll upwards</h2> <p> Qui minima doloribus ut dolore iure qui debitis voluptatibus aut dolore nostrum hic consequatur. Sed consequatur nemo qui ipsum enim et velit architecto sit perferendis repellendus. </p> <p> Sed deserunt voluptatum et voluptate voluptatem aut labore reprehenderit vel corporis sapiente. 33 omnis magnam et ratione saepe aut dicta veritatis rem voluptatem necessitatibus aut voluptates autem est sunt delectus aut commodi doloribus. </p> <p> <a href="#top">Scroll to top</a> </p> </div> </div> </div> <style>{` .toc-demo-layout h2:first-child { margin-top: 12px } @media (min-width: 960px) { .toc-demo-layout { display: grid; grid-template-columns: 1fr auto; gap: 1rem; margin-block: 2rem 10rem; place-items: start; } .toc-demo-layout > :first-child { grid-column-start: 2; } .toc-demo-layout > :last-child { grid-row-start: 1; grid-column-start: 1; } } `}</style> </> ); }