
Product
Introducing Socket Firewall: Free, Proactive Protection for Your Software Supply Chain
Socket Firewall is a free tool that blocks malicious packages at install time, giving developers proactive protection against rising supply chain attacks.
@harshiniravikumar/react-footnote-system
Advanced tools
A fully featured, customizable, and accessible footnote management system for React applications with TypeScript support
A fully featured, customizable, and accessible footnote management system for React applications. Provides automatic numbering, context-based management, and flexible rendering with TypeScript support for modern web development.
npm install "@harshiniravikumar/react-footnote-system"
Component | Type | Description |
---|---|---|
FootnoteContext | Provider | Context provider for footnote management |
FootnoteReference | Component | Creates footnote references with automatic numbering |
FootnoteList | Component | Renders all registered footnotes in list format |
Footnote | Component | Standalone footnote component for advanced use cases |
Prop | Type | Default | Description |
---|---|---|---|
id | string | - | Unique identifier for the footnote (required) |
children | ReactNode | - | The footnote content |
className | string | '' | Additional CSS classes for the reference |
onClick | () => void | - | Custom click handler |
style | CSSProperties | {} | Inline styles for the reference |
renderReference | (number: number) => ReactNode | - | Custom reference renderer |
Prop | Type | Default | Description |
---|---|---|---|
className | string | '' | CSS classes for the list container |
itemClassName | string | '' | CSS classes for footnote items |
title | string | "Footnotes" | Title for the footnote section |
showTitle | boolean | true | Whether to display the title |
orderBy | "appearance" | "alphabetical" | "appearance" | Footnote ordering method |
renderItem | (footnote: FootnoteData) => ReactNode | - | Custom footnote item renderer |
Prop | Type | Default | Description |
---|---|---|---|
id | string | - | Unique identifier (required) |
content | string | ReactNode | - | Footnote content |
number | number | - | Manual footnote number override |
autoRegister | boolean | true | Automatically register with context |
Option | Type | Default | Description |
---|---|---|---|
startNumber | number | 1 | Starting number for footnote numbering |
numberingStyle | "numeric" | "roman" | "alpha" | "numeric" | Numbering style for footnotes |
allowDuplicates | boolean | false | Allow duplicate footnote IDs |
resetOnUnmount | boolean | false | Reset footnotes when context unmounts |
maxFootnotes | number | undefined | Maximum number of footnotes allowed |
Customize the visual appearance of your footnotes:
const footnoteTheme = {
reference: {
color: "#007bff",
fontSize: "0.8em",
verticalAlign: "super",
textDecoration: "none",
padding: "0 2px",
borderRadius: "2px",
backgroundColor: "transparent"
},
list: {
borderTop: "1px solid #e0e0e0",
marginTop: "2rem",
paddingTop: "1rem",
fontSize: "0.9em"
},
item: {
marginBottom: "0.5rem",
lineHeight: "1.4",
color: "#666"
},
title: {
fontSize: "1.1em",
fontWeight: "bold",
marginBottom: "1rem",
color: "#333"
}
};
import React from 'react';
import {
FootnoteContext,
FootnoteReference,
FootnoteList
} from "@your-username/react-footnote-system";
function BasicExample() {
return (
<FootnoteContext>
<article>
<h1>Article Title</h1>
<p>
This is some content with a footnote
<FootnoteReference id="note1">
This appears as footnote #1 at the bottom of the page.
</FootnoteReference>
and more text continues here.
</p>
<p>
Another paragraph with another reference
<FootnoteReference id="note2">
This becomes footnote #2 with automatic numbering.
</FootnoteReference>
in the middle of the sentence.
</p>
<FootnoteList />
</article>
</FootnoteContext>
);
}
import React, { useRef, useContext } from 'react';
import {
FootnoteContext,
FootnoteReference,
FootnoteList,
useFootnoteContext
} from "@your-username/react-footnote-system";
function AdvancedExample() {
const footnoteContext = useFootnoteContext();
const handleFootnoteClick = (id: string) => {
console.log('Footnote clicked:', id);
};
return (
<FootnoteContext
options={{
startNumber: 1,
numberingStyle: "numeric",
allowDuplicates: false,
resetOnUnmount: true,
maxFootnotes: 50
}}
theme={{
reference: {
color: "#0066cc",
backgroundColor: "#f0f8ff",
borderRadius: "4px",
padding: "2px 4px"
},
list: {
borderTop: "2px solid #0066cc",
backgroundColor: "#fafafa"
}
}}
>
<main>
<section>
<h1>Research Paper</h1>
<p>
Recent studies show significant findings
<FootnoteReference
id="study-2024"
onClick={() => handleFootnoteClick("study-2024")}
className="custom-reference"
>
Smith, J., & Johnson, A. (2024). "Advanced Research Methods in Modern Science."
<em>Journal of Scientific Discovery</em>, 42(3), 123-145.
DOI: 10.1000/journal.2024.123
</FootnoteReference>
that support our hypothesis.
</p>
<p>
The methodology employed
<FootnoteReference id="methodology">
Our research methodology followed the guidelines established by
the International Research Standards Committee (IRSC).
</FootnoteReference>
ensures reliable results across multiple scenarios.
</p>
</section>
<footer>
<FootnoteList
title="References & Notes"
className="research-footnotes"
itemClassName="footnote-item"
showTitle={true}
orderBy="appearance"
renderItem={(footnote) => (
<div className="custom-footnote">
<span className="footnote-number">{footnote.number}.</span>
<span className="footnote-content">{footnote.content}</span>
</div>
)}
/>
</footer>
</main>
</FootnoteContext>
);
}
function MultiSectionDocument() {
return (
<div>
{/* Chapter 1 with independent footnotes */}
<FootnoteContext options={{ startNumber: 1 }}>
<section>
<h2>Chapter 1: Introduction</h2>
<p>
Content with footnotes
<FootnoteReference id="ch1-intro">
Introduction footnote content here.
</FootnoteReference>
specific to this chapter.
</p>
<FootnoteList title="Chapter 1 Notes" />
</section>
</FootnoteContext>
<FootnoteContext options={{ startNumber: 1, numberingStyle: "roman" }}>
<section>
<h2>Chapter 2: Methodology</h2>
<p>
Different chapter content
<FootnoteReference id="ch2-method">
Methodology footnote with roman numerals.
</FootnoteReference>
with separate footnote numbering.
</p>
<FootnoteList title="Chapter 2 Notes" />
</section>
</FootnoteContext>
</div>
);
}
function CustomFootnoteExample() {
return (
<FootnoteContext>
<div>
<p>
Text with custom reference
<FootnoteReference
id="custom"
renderReference={(number) => (
<span className="custom-ref">
[{number}]
</span>
)}
>
Custom styled footnote content
</FootnoteReference>
</p>
<FootnoteList
renderItem={(footnote) => (
<div className="animated-footnote">
<strong>{footnote.number}.</strong>
<span>{footnote.content}</span>
</div>
)}
/>
</div>
</FootnoteContext>
);
}
Callback | Type | Description |
---|---|---|
onFootnoteRegister | (id: string, content: ReactNode) => void | Called when footnote is registered |
onFootnoteUnregister | (id: string) => void | Called when footnote is unregistered |
onFootnoteClick | (id: string, number: number) => void | Called when footnote reference is clicked |
onListRender | (footnotes: FootnoteData[]) => void | Called when footnote list renders |
onMaxFootnotesReached | () => void | Called when max footnotes limit is reached |
Access footnote context methods and state:
Method/Property | Type | Description |
---|---|---|
footnotes | FootnoteData[] | Array of all registered footnotes |
register | (id: string, content: ReactNode) => void | Register a new footnote |
unregister | (id: string) => void | Unregister a footnote |
getFootnote | (id: string) => FootnoteData | undefined | Get footnote by ID |
getFootnoteNumber | (id: string) => number | undefined | Get footnote number by ID |
reset | () => void | Clear all footnotes |
count | number | Total number of registered footnotes |
import { useFootnoteContext } from "@your-username/react-footnote-system";
function FootnoteStats() {
const { footnotes, count, reset } = useFootnoteContext();
return (
<div>
<p>Total footnotes: {count}</p>
<button onClick={reset}>Clear All Footnotes</button>
</div>
);
}
<FootnoteContext options={{ numberingStyle: "numeric" }}>
<article className="academic-paper">
<h1>The Impact of Climate Change on Marine Ecosystems</h1>
<p>
Recent oceanographic studies
<FootnoteReference id="ocean-study-2024">
Martinez, C., et al. (2024). "Ocean Temperature Variations and Marine Biodiversity."
<em>Marine Biology Quarterly</em>, 78(2), 45-67.
</FootnoteReference>
indicate significant temperature variations in coastal waters.
</p>
<p>
These findings corroborate earlier research
<FootnoteReference id="previous-research">
See Thompson, R. (2022) and Williams, S. (2023) for comprehensive
reviews of historical temperature data.
</FootnoteReference>
from the past decade.
</p>
<FootnoteList title="References" className="academic-references" />
</article>
</FootnoteContext>
<FootnoteContext options={{ numberingStyle: "alpha" }}>
<article className="blog-post">
<h1>Understanding React Hooks</h1>
<p>
React Hooks revolutionized functional components
<FootnoteReference id="hooks-intro">
Hooks were introduced in React 16.8 (February 2019) and allow you to
use state and other React features in functional components.
</FootnoteReference>
by enabling state management without classes.
</p>
<p>
The useState hook
<FootnoteReference id="usestate-example">
<code>const [state, setState] = useState(initialValue)</code> is the
most commonly used hook for managing component state.
</FootnoteReference>
is fundamental to modern React development.
</p>
<FootnoteList
title="Additional Information"
className="blog-footnotes"
showTitle={true}
/>
</article>
</FootnoteContext>
<FootnoteContext options={{ numberingStyle: "roman" }}>
<div className="legal-document">
<h1>Terms of Service</h1>
<section>
<h2>Section 1: Definitions</h2>
<p>
"Service" refers to the platform
<FootnoteReference id="service-definition">
As defined under applicable consumer protection laws and regulations
in the jurisdiction where the service is provided.
</FootnoteReference>
provided by the Company.
</p>
</section>
<FootnoteList
title="Legal References"
className="legal-footnotes"
itemClassName="legal-footnote-item"
/>
</div>
</FootnoteContext>
.modern-footnotes .footnote-reference {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 6px;
padding: 2px 6px;
color: #007bff;
text-decoration: none;
transition: all 0.2s ease;
}
.modern-footnotes .footnote-reference:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.modern-footnotes .footnote-list {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
}
.academic-footnotes .footnote-reference {
color: #d32f2f;
font-weight: 500;
vertical-align: super;
font-size: 0.75em;
text-decoration: none;
border-bottom: 1px dotted #d32f2f;
}
.academic-footnotes .footnote-list {
border-top: 2px solid #333;
margin-top: 3rem;
padding-top: 1rem;
font-family: 'Times New Roman', serif;
}
.academic-footnotes .footnote-item {
text-indent: -1em;
padding-left: 1em;
margin-bottom: 0.8rem;
}
function ResponsiveFootnotes() {
return (
<FootnoteContext>
<div className="responsive-content">
<p>
Mobile-optimized footnotes
<FootnoteReference
id="mobile-note"
className="responsive-reference"
>
On mobile devices, footnotes adapt to smaller screens with
optimized touch targets and readable font sizes.
</FootnoteReference>
work seamlessly across devices.
</p>
<FootnoteList className="responsive-footnote-list" />
</div>
</FootnoteContext>
);
}
@media (max-width: 768px) {
.responsive-reference {
font-size: 0.9em !important;
padding: 4px 6px !important;
}
.responsive-footnote-list {
font-size: 0.85em;
padding: 1rem 0.5rem;
}
}
<FootnoteReference
id="accessible-note"
aria-label="Footnote reference 1"
role="doc-noteref"
>
Accessible footnote content
</FootnoteReference>
Comprehensive TypeScript definitions included:
import type {
Footnotes,
FootnoteProps,
FootnoteContextType,
FootnoteRefProps,
FootnoteListProps,
FootnoteData,
FootnoteOptions,
FootnoteTheme
} from "@your-username/react-footnote-system";
interface CustomFootnoteData {
id: string;
content: string;
category: 'reference' | 'explanation' | 'source';
}
const MyComponent: React.FC = () => {
const [footnotes, setFootnotes] = useState<CustomFootnoteData[]>([]);
return (
<FootnoteContext>
{/* Your footnote implementation */}
</FootnoteContext>
);
};
<FootnoteContext options={{ numberingStyle: "numeric" }}>
{/* Footnotes appear as: 1, 2, 3, ... */}
</FootnoteContext>
<FootnoteContext options={{ numberingStyle: "roman" }}>
{/* Footnotes appear as: i, ii, iii, ... */}
</FootnoteContext>
<FootnoteContext options={{ numberingStyle: "alpha" }}>
{/* Footnotes appear as: a, b, c, ... */}
</FootnoteContext>
<FootnoteContext options={{ startNumber: 10 }}>
{/* Footnotes start from: 10, 11, 12, ... */}
</FootnoteContext>
function InteractiveFootnotes() {
const [selectedFootnote, setSelectedFootnote] = useState<string | null>(null);
return (
<FootnoteContext>
<div>
<p>
Click this footnote
<FootnoteReference
id="interactive"
onClick={() => setSelectedFootnote("interactive")}
>
This footnote has custom click behavior and can trigger actions
in your application.
</FootnoteReference>
to see custom behavior.
</p>
{selectedFootnote && (
<div className="footnote-popup">
<p>You clicked footnote: {selectedFootnote}</p>
<button onClick={() => setSelectedFootnote(null)}>Close</button>
</div>
)}
<FootnoteList />
</div>
</FootnoteContext>
);
}
function DynamicFootnotes() {
const { register, unregister, footnotes, reset } = useFootnoteContext();
const addDynamicFootnote = () => {
const id = `dynamic-${Date.now()}`;
register(id, `Dynamic footnote added at ${new Date().toLocaleTimeString()}`);
};
return (
<div>
<button onClick={addDynamicFootnote}>Add Footnote</button>
<button onClick={reset}>Clear All</button>
<p>Current footnotes: {footnotes.length}</p>
<FootnoteList />
</div>
);
}
import ReactMarkdown from 'react-markdown';
function MarkdownWithFootnotes({ content }: { content: string }) {
return (
<FootnoteContext>
<ReactMarkdown
components={{
sup: ({ children }) => (
<FootnoteReference id={`md-${children}`}>
Markdown footnote content
</FootnoteReference>
)
}}
>
{content}
</ReactMarkdown>
<FootnoteList />
</FootnoteContext>
);
}
function CMSContent({ content }: { content: any[] }) {
return (
<FootnoteContext>
{content.map((block, index) => {
if (block.type === 'footnote') {
return (
<FootnoteReference key={index} id={block.id}>
{block.content}
</FootnoteReference>
);
}
return <div key={index}>{block.content}</div>;
})}
<FootnoteList />
</FootnoteContext>
);
}
import { render, screen } from '@testing-library/react';
import { FootnoteContext, FootnoteReference, FootnoteList } from 'your-library';
test('footnotes render correctly', () => {
render(
<FootnoteContext>
<FootnoteReference id="test">Test footnote</FootnoteReference>
<FootnoteList />
</FootnoteContext>
);
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('Test footnote')).toBeInTheDocument();
});
MIT License - feel free to use in your projects!
FAQs
A fully featured, customizable, and accessible footnote management system for React applications with TypeScript support
We found that @harshiniravikumar/react-footnote-system demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket Firewall is a free tool that blocks malicious packages at install time, giving developers proactive protection against rising supply chain attacks.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.