Created
October 28, 2023 15:44
-
-
Save zelaznik/c7b9f3bb557a368370ae0605460f0d47 to your computer and use it in GitHub Desktop.
Nested header tags in React
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import NestedHeader from "./NestedHeader.tsx" | |
function SomeChildComponent() { | |
return ( | |
<NestedHeader content="Still keeps track globally of how many heading levels deep you are"> | |
<p> | |
This is the power of this abstraction. Child components can use NestedHeader. | |
and the header level will always be correct, one level more than its parent. | |
</p> | |
</NestedHeader> | |
) | |
} | |
function App() { | |
return ( | |
<h1>We still use the plain old HTML tag for h1. There should be only one per page.</h1> | |
<p>The logic is easier if we start at h2 for nested headers.</p> | |
<NestedHeader content="(h2) we can pass it a text-only header such as this"> | |
<NestedHeader content={<><strong>(h3)</strong> We can also pass it a jsx value</>}> | |
<p>The children of the NestedHeader component will appear AFTER the h tag</p> | |
</NestedHeader> | |
<NestedHeader className="hello-world" content="Arbitrary attributes are passed along"> | |
<p>The children of the NestedHeader component will appear AFTER the h tag</p> | |
</NestedHeader> | |
<NestedHeader content={(Hx) => ( | |
<header> | |
<Hx className="foo-bar">More complicated headers</Hx> | |
<p>The function Hx is a React component that automatically returns h1 through h6</p> | |
<p>By passing a function into "content", you can be more flexible with where you place the h1-h6</p> | |
</header> | |
)}> | |
<p>The children of the header component will still appear AFTER the result of the function</p> | |
<SomeChildComponent /> | |
</NestedHeader> | |
</NestedHeader> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useContext, createContext } from "react"; | |
const NestedHeaderContext = createContext<number>(2); | |
type HxCallback = (component: typeof Hx) => React.ReactNode; | |
type HxProps = { | |
children: React.ReactNode; | |
[x: string]: any; | |
}; | |
type NestedHeaderProps = { | |
content: string | React.ReactNode | HxCallback; | |
children?: React.ReactNode; | |
[x: string]: any; | |
}; | |
export function Hx({ children, ...props }: HxProps) { | |
const level = useContext(NestedHeaderContext); | |
const tag = "h" + Math.min(level, 6); | |
return React.createElement(tag, props, children); | |
} | |
export default function NestedHeader({ | |
content, | |
children, | |
...props | |
}: NestedHeaderProps) { | |
const level = useContext(NestedHeaderContext); | |
let Header; | |
if (typeof content === "function") { | |
Header = content(Hx); | |
} else { | |
Header = <Hx {...props}>{content}</Hx>; | |
} | |
return ( | |
<> | |
{Header} | |
<NestedHeaderContext.Provider value={level + 1}> | |
{children} | |
</NestedHeaderContext.Provider> | |
</> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<body> | |
<div id="root"> | |
<h1>We still use the plain old HTML tag for h1. There should be only one per page.</h1> | |
<p>The logic is easier if we start at h2 for nested headers.</p> | |
<h2>(h2) we can pass it a text-only header such as this</h2> | |
<h3><strong>(h3)</strong> We can also pass it a jsx value</h3> | |
<p>The children of the NestedHeader component will appear AFTER the h tag</p> | |
<!-- end H3 --> | |
<h3 class="hello-world">Arbitrary attributes are passed along</h3> | |
<p>The children of the NestedHeader component will appear AFTER the h tag</p> | |
<!-- end H3 --> | |
<header> | |
<h3 class="foo-bar">More complicated headers</h3> | |
<p>The function Hx is a React component that automatically returns h1 through h6</p> | |
<p>By passing a function into "content", you can be more flexible with where you place the h1-h6</p> | |
</header> | |
<p>The children of the NestedHeader component will still appear AFTER the h tag</p> | |
<h4>Still keeps track globally of how many heading levels deep you are</h4> | |
<p> | |
This is the power of this abstraction. Child components can use NestedHeader. | |
and the header level will always be correct, one level more than its parent. | |
</p> | |
<!-- end H4 --> | |
<!-- end H3 --> | |
<!-- end H2 --> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment