<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Google Docs - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Google Docs - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:20:40 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/google-docs/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Write Math Equations in Google Docs ]]>
                </title>
                <description>
                    <![CDATA[ Math equations are a critical part of academic papers, research reports, and technical documentation. While LaTeX is widely used for professional typesetting, Google Docs offers a robust set of features for inserting and formatting math equations and... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/write-math-equations-in-google-docs/</link>
                <guid isPermaLink="false">68275cf15ed8a1db0cf8769b</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mathematics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chatgpt ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chatgptguide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MathJax ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikram Aruchamy ]]>
                </dc:creator>
                <pubDate>Fri, 16 May 2025 15:42:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747410133881/93c8cf6e-6cbb-4890-8023-fcc2fdaa0fa2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Math equations are a critical part of academic papers, research reports, and technical documentation. While LaTeX is widely used for professional typesetting, Google Docs offers a robust set of features for inserting and formatting math equations and also supports LaTeX-style input.</p>
<p>Whether you're a student submitting a math assignment or a professional documenting formulas, Google Docs provides multiple ways to insert and format equations efficiently.</p>
<p>In this article, you'll learn how to <a target="_blank" href="https://support.google.com/docs/answer/160749">write math equations in Google Docs</a> using different methods, including using Google Docs’ built-in equation editor and typing LaTeX-style commands directly, inserting complex equations with the help of the Auto-LaTeX add-on, and copying math equations from <a target="_blank" href="https://chromewebstore.google.com/detail/chatgpt-to-google-docs-or/oibghjgooccojibfacdonaoipegckdeg">ChatGPT to Google Docs</a> without losing formatting by using the ChatGPT to Google Docs or PDF Chrome extension.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-write-equations-using-the-built-in-equation-editor">How to Write Equations Using the Built-in Equation Editor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-equations-using-latex-commands">How to Write Equations Using LaTeX Commands</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-auto-latex-add-on-for-writing-advanced-math-equations">How to Use Auto Latex Add-on for Writing Advanced Math Equations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-copy-math-equations-from-chatgpt-to-google-docs">How to Copy Math Equations from ChatGPT to Google Docs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-watch-how-to-write-equations-in-google-docs">Watch: How to Write Equations in Google Docs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tips-for-formatting-math-equations-in-google-docs">Tips for Formatting Math Equations in Google Docs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-to-write-equations-using-the-built-in-equation-editor"><strong>How to Write Equations Using the Built-in Equation Editor</strong></h2>
<p>Google Docs has a built-in equation editor that makes it easy to insert mathematical symbols and expressions.</p>
<p>To insert an equation editor box:</p>
<ol>
<li><p>Open your Google Docs document.</p>
</li>
<li><p>Go to the top menu and click <em>Insert</em> → <em>Equation</em>.</p>
</li>
<li><p>An equation editor will appear, and a new toolbar will show up with common math symbols like fractions, exponents, Greek letters, and more.</p>
</li>
</ol>
<p>Alternatively, you can use the following keyboard shortcuts to insert an equation editor box. </p>
<ul>
<li><p><strong>Windows/Linux:</strong> <code>Alt</code> + <code>I</code>, then <code>E</code></p>
</li>
<li><p><strong>Mac:</strong> <code>Control</code> + <code>Option</code> + <code>I</code>, then <code>E</code></p>
</li>
</ul>
<p>This shortcut quickly opens the equation editor without clicking through menus.</p>
<p><strong>Toolbar Symbols:</strong></p>
<p>Once the toolbar appears, you’ll find buttons for:</p>
<ul>
<li><p>Greek letters</p>
</li>
<li><p>Miscellaneous operations</p>
</li>
<li><p>Relations</p>
</li>
<li><p>Math operations</p>
</li>
<li><p>Arrows</p>
</li>
</ul>
<p>The equation editor box and a toolbar look like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747198733591/9defa152-16a5-42a1-b098-228a9d1f7f79.png" alt="Google Docs Equation Editor and Toolbar" class="image--center mx-auto" width="1340" height="450" loading="lazy"></p>
<p>Now let’s learn how to write equations using the equation editor with a practical example.</p>
<h3 id="heading-example-typing-the-quadratic-formula">Example: Typing the Quadratic Formula</h3>
<p>Follow these steps to insert the following quadratic formula in Google Docs:</p>
<p>$$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$</p><ol>
<li><p>Go to <em>Insert</em> → <em>Equation</em> to insert an equation editor and enable the equation toolbar.</p>
</li>
<li><p>Type <code>x=</code></p>
</li>
<li><p>Click the Math Operations dropdown (the one with templates like square roots, brackets), then select the fraction template. This inserts a placeholder with two parts: a numerator and a denominator.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747199319708/142157c9-f997-494a-be4a-efb619b7c12d.png" alt="Screenshot of Google Docs displaying a feature to insert math equations. A dropdown menu shows various mathematical symbols like fractions, square roots, and integrals. " class="image--center mx-auto" width="721" height="418" loading="lazy"></p>
</li>
<li><p>Click inside the numerator field. Begin by typing <code>-b</code>.</p>
</li>
<li><p>Now insert the ± (plus-minus) symbol. To do this:</p>
<ul>
<li><p>Click the Miscellaneous Operations dropdown</p>
</li>
<li><p>Select the ± symbol from the list.<br>  Your numerator should now show: <code>-b ±</code> as in the following image:</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747199567908/be5daee7-2ed2-4c86-be16-d90e033a05be.png" alt="Screenshot of Google Docs showing a math equation being edited with the equation toolbar open. Various symbols are visible on the toolbar, and part of a quadratic formula is visible in the document area." class="image--center mx-auto" width="766" height="362" loading="lazy"></p>
</li>
</ul>
</li>
<li><p>After the ± symbol, insert a square root:</p>
<ul>
<li><p>Go back to the Math Operations dropdown and select the square root template.</p>
</li>
<li><p>Inside the root, type <code>b^2 - 4ac</code>.</p>
<ul>
<li><p>Use <code>^</code> to enter exponents. For example, <code>b^2</code> will be rendered as <em>b²</em>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747199681755/cc2084c2-5856-4999-9905-d825b5c276d9.png" alt="Screenshot of Google Docs showing a math equation being inserted. A dropdown menu displays mathematical symbols like fractions, square roots, and integrals. A formula for the quadratic equation is in the document area on the right." class="image--center mx-auto" width="775" height="393" loading="lazy"></p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Move to the denominator field and type <code>2a</code>.</p>
</li>
</ol>
<p>Now your full equation should appear as:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747199739733/2c1ef4f8-9730-491f-9120-5ba6daee41c3.png" alt="Screenshot of Google Docs showing an open document. It has menu options at the top and a formula for the quadratic equation displayed on the page." class="image--center mx-auto" width="805" height="352" loading="lazy"></p>
<p>The equation will be properly formatted using Google Docs’ equation rendering, making it easy to read and mathematically accurate. You can continue typing more text below or beside the equation as needed – it behaves like any other element in your document.</p>
<p>This approach is useful for inserting neatly formatted equations without relying on add-ons or external tools. It’s especially helpful for students, teachers, and professionals preparing technical documents directly in Google Docs.</p>
<h2 id="heading-how-to-write-equations-using-latex-commands">How to Write Equations Using LaTeX Commands</h2>
<p>If you're familiar with <a target="_blank" href="https://www.latex-project.org/"><strong>LaTeX</strong></a>, you can take advantage of Google Docs’ support for a subset of LaTeX-style commands inside the built-in equation editor. This can greatly speed up the process of entering complex mathematical expressions, especially if you're already comfortable with LaTeX syntax.</p>
<h3 id="heading-how-to-use-latex-commands-in-google-docs">How to Use LaTeX Commands in Google Docs</h3>
<ol>
<li><p>Open your Google Docs document.</p>
</li>
<li><p>Go to Insert → Equation to activate the equation toolbar and equation input field.</p>
</li>
<li><p>Click inside the equation box. Instead of using the toolbar buttons, type LaTeX-style commands directly.</p>
</li>
<li><p>As you type, Google Docs will automatically render the commands into formatted math once you press space or enter after each command or expression.</p>
</li>
</ol>
<h4 id="heading-commonly-supported-latex-commands-in-google-docs">Commonly Supported LaTeX Commands in Google Docs:</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Instruction</strong></td><td><strong>Result</strong></td></tr>
</thead>
<tbody>
<tr>
<td>To insert a fraction</td><td><code>\frac{a}{b}</code> → 𝑎⁄𝑏</td></tr>
<tr>
<td>To insert a square root</td><td><code>\sqrt{x}</code> → √𝑥</td></tr>
<tr>
<td>To insert Greek letters like α, β</td><td><code>\alpha, \beta</code> → α, β</td></tr>
<tr>
<td>To insert an integral with limits</td><td><code>\int_a^b f(x)\,dx</code> → ∫ᵃᵇ 𝑓(𝑥) 𝑑𝑥</td></tr>
<tr>
<td>To insert x superscript 2</td><td><code>x^2</code> → 𝑥²</td></tr>
<tr>
<td>To insert x subscript 1</td><td><code>x_1</code> → 𝑥₁</td></tr>
</tbody>
</table>
</div><p>Type these commands in the equation box, and when you press space or enter, they will be converted to properly formatted mathematical notation.</p>
<h4 id="heading-example-typing-the-quadratic-formula-using-latex-commands">Example: Typing the Quadratic Formula Using LaTeX Commands</h4>
<p>Let’s walk through how to enter the following quadratic formula using LaTeX-style commands:</p>
<p>$$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$</p><p><strong>Steps:</strong></p>
<ol>
<li><p>Insert the equation box: Go to Insert → Equation.</p>
</li>
<li><p>In the equation input area, type the following:</p>
</li>
</ol>
<pre><code class="lang-javascript">x = \frac{-b \pm \sqrt{b^<span class="hljs-number">2</span> - <span class="hljs-number">4</span>ac}}{<span class="hljs-number">2</span>a}
</code></pre>
<ul>
<li><p><code>\frac</code> creates a fraction.</p>
</li>
<li><p><code>-b</code> is the numerator’s first term.</p>
</li>
<li><p><code>\pm</code> inserts the plus-minus symbol.</p>
</li>
<li><p><code>\sqrt</code> creates a square root.</p>
</li>
<li><p><code>b^2</code> formats <em>b squared</em>.</p>
</li>
<li><p><code>- 4ac</code> is written normally inside the square root.</p>
</li>
<li><p><code>2a</code> is the denominator.</p>
</li>
</ul>
<ol start="3">
<li>As you type, press space or enter after each LaTeX command. Google Docs will automatically convert the code into properly formatted math notation.</li>
</ol>
<p>After rendering, the equation will appear as:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747199739733/2c1ef4f8-9730-491f-9120-5ba6daee41c3.png" alt="A Google Docs interface showing the quadratic formula being entered as a math equation" width="805" height="352" loading="lazy"></p>
<p>This method is ideal for users who prefer keyboard-based input over clicking toolbar icons. It also allows you to enter complex expressions faster and more accurately, especially if you're familiar with standard LaTeX syntax.</p>
<h4 id="heading-notes">Notes:</h4>
<ul>
<li><p>Not all LaTeX features are supported in Google Docs. The supported commands are limited to basic math formatting, Greek letters, and common symbols.</p>
</li>
<li><p>Make sure to press <strong>space</strong> after each LaTeX command so that Docs knows to render it.</p>
</li>
</ul>
<h2 id="heading-how-to-use-auto-latex-add-on-for-writing-advanced-math-equations">How to Use Auto Latex Add-on for Writing Advanced Math Equations</h2>
<p>When generating mathematical content using tools like ChatGPT, you'll notice that equations are <strong>rendered visually on the webpage</strong>, but behind the scenes they’re created using <a target="_blank" href="https://www.latex-project.org/">LaTeX</a> code. So when you copy content from ChatGPT into Google Docs, the equations come through as raw LaTeX code rather than rendered math expressions.</p>
<p>For example, a quadratic formula provided by ChatGPT might look like this when pasted into your document:</p>
<pre><code class="lang-javascript">x = \frac{-b \pm \sqrt{b^<span class="hljs-number">2</span> - <span class="hljs-number">4</span>ac}}{<span class="hljs-number">2</span>a}
</code></pre>
<p>While this format is ideal for precision, Google Docs doesn’t support LaTeX rendering by default.</p>
<p>This is where the <strong>Auto-LaTeX Equations</strong> add-on becomes essential, especially if you're moving content from <a target="_blank" href="https://www.docstomarkdown.pro/chatgpt-to-google-docs/">ChatGPT to Google Docs</a>. It’s also incredibly useful when importing LaTeX-based documents into Google Docs, such as content originally written in <a target="_blank" href="https://overleaf.com/">Overleaf</a> or other LaTeX editors.</p>
<p>Instead of manually reformatting equations, the add-on automatically renders LaTeX code into properly formatted math equations, preserving the typesetting and structure you’d expect from a LaTeX environment.</p>
<h3 id="heading-what-is-auto-latex-equations">What is Auto-LaTeX Equations?</h3>
<p><a target="_blank" href="https://workspace.google.com/marketplace/app/autolatex_equations/850293439076"><strong>Auto-LaTeX Equations</strong></a> is a free and open-source Google Docs add-on that scans your document for LaTeX expressions and converts them into a properly formatted equations.</p>
<p>It recognizes LaTeX code wrapped in these delimiters:</p>
<ul>
<li><p>Inline: <code>$$ ... $$</code></p>
</li>
<li><p>Display: <code>\[ ... \]</code></p>
</li>
</ul>
<p>Once detected, it renders the equations seamlessly within your document, eliminating the need to retype or manually format them.</p>
<ol>
<li><p>Paste your LaTeX expression into the Google Docs document. Make sure the expression is enclosed using one of the supported delimiters:</p>
<p> <code>$$ ... $$ or \[ ... \]</code></p>
</li>
<li><p>Open the add-on sidebar by clicking Extensions <strong>→</strong> Auto-LaTeX Equations <strong>→</strong> Start.</p>
</li>
<li><p>Once the sidebar opens, you’ll see a dropdown labeled “Delimiters” and a button called “Render Equations.”</p>
</li>
<li><p>Select the delimiter you used when enclosing your LaTeX equations – for example, <code>$$</code> or <code>\[ \]</code>.</p>
</li>
<li><p>Click the “Render Equations” button.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747203253430/e96fe9ac-ccba-4ed5-ab10-1e759d737d7d.png" alt="Auto Latex Equations add-on sidebar" class="image--center mx-auto" width="297" height="387" loading="lazy"></p>
<p>The add-on will automatically scan your document and convert all valid LaTeX expressions into properly formatted equation images.</p>
<p>This step-by-step process allows you to take any LaTeX-based math copied from ChatGPT and render it cleanly within Google Docs – ready for export to Word or PDF.</p>
<h3 id="heading-example-converting-a-latex-coded-equation-to-rendered-math-equations">Example: Converting a LaTeX coded Equation to Rendered Math Equations</h3>
<p>Paste the following equation into Google Docs:</p>
<p><code>$$ x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$</code></p>
<p>To convert it:</p>
<ol>
<li><p>Go to Extensions → Auto-LaTeX Equations → Start.</p>
</li>
<li><p>Select the Delimitor as <code>$$</code> ..<code>$$</code> and click on the Render Equations button. The equation will be rendered and look as follows:</p>
</li>
</ol>
<p>$$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$</p><h4 id="heading-how-to-install-auto-latex-equations">How to Install Auto-LaTeX Equations</h4>
<ol>
<li><p>In Google Docs, click Extensions → Add-ons → Get add-ons.</p>
</li>
<li><p>Search for Auto-LaTeX Equations.</p>
</li>
<li><p>Click Install and follow the prompts.</p>
</li>
<li><p>After installation, access it from Extensions → Auto-LaTeX Equations.</p>
</li>
</ol>
<h2 id="heading-how-to-copy-math-equations-from-chatgpt-to-google-docs">How to Copy Math Equations from ChatGPT to Google Docs</h2>
<p>To easily transfer math equations and the surrounding content from ChatGPT into Google Docs without losing formatting, use the free <a target="_blank" href="https://chromewebstore.google.com/detail/chatgpt-to-google-docs-or/oibghjgooccojibfacdonaoipegckdeg"><strong>ChatGPT to Google Docs or PDF</strong></a> Chrome extension.</p>
<p>This extension allows you to:</p>
<ul>
<li><p>Export a single response (with equations and tables) into Google Docs while preserving formatting</p>
</li>
<li><p>Export an entire conversation, including math, code, and text, into a clean, one organized Google Docs, no need to export responses separately and <a target="_blank" href="https://www.freecodecamp.org/news/merge-multiple-google-docs-with-apps-script-or-google-docs-api/">merge multiple Google Docs into one</a> later</p>
</li>
<li><p>Save ChatGPT canvas content as a Google Docs or PDF</p>
</li>
<li><p>Export ChatGPT deep research documents directly into Google Docs</p>
</li>
<li><p>Export <a target="_blank" href="https://www.docstomarkdown.pro/chatgpt-to-pdf/">ChatGPT content directly into PDF format</a> when no further edits are necessary, eliminating the need to first export to Google Docs and then convert <a target="_blank" href="https://workspace.google.com/marketplace/app/docs_to_pdf_pro/302636103705">Google Docs to PDF</a></p>
</li>
</ul>
<p>It’s especially useful for students, researchers, and professionals who want to keep their AI-generated math, notes, and research well-organized in Google Docs or PDF format with minimal effort.</p>
<h2 id="heading-watch-how-to-write-equations-in-google-docs">Watch: How to Write Equations in Google Docs</h2>
<p>If you prefer visual learning, here’s a helpful video walkthrough that demonstrates all the methods discussed above – using the built-in equation editor, LaTeX-like commands, and the Auto-LaTeX Equations add-on.</p>
<p>This step-by-step tutorial covers:</p>
<ul>
<li><p>Opening and using the built-in equation toolbar</p>
</li>
<li><p>Typing LaTeX-style commands directly in the equation editor</p>
</li>
<li><p>Converting AI-generated LaTeX (e.g., from ChatGPT) into clean equations</p>
</li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Y_2q45Qscp0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-tips-for-formatting-math-equations-in-google-docs">Tips for Formatting Math Equations in Google Docs</h2>
<p><strong>Use inline equations when:</strong></p>
<ul>
<li><p>Inserting short expressions like <code>x²</code>, <code>a/b</code>, or single variables</p>
</li>
<li><p>Including math within a sentence to maintain the flow of text</p>
</li>
</ul>
<p><strong>Use block equations when:</strong></p>
<ul>
<li><p>Writing complex or multi-line formulas (e.g., the quadratic formula)</p>
</li>
<li><p>You want the equation to be clearly separated from the surrounding text for readability</p>
</li>
</ul>
<p><strong>Wrapping tips for rendered equations:</strong></p>
<ul>
<li><p>Rendered equations are treated as images in Google Docs, which may disrupt the document layout if not positioned correctly</p>
</li>
<li><p>To fix this:</p>
<ul>
<li><p>Click the equation image</p>
</li>
<li><p>Choose from:</p>
<ul>
<li><p><strong>In line</strong> – aligns the equation with surrounding text (best for inline use)</p>
</li>
<li><p><strong>Wrap text</strong> – wraps paragraph text around the equation image</p>
</li>
<li><p><strong>Break text</strong> – places the equation on its own line, isolating it</p>
</li>
</ul>
</li>
<li><p>Use the margin handles or spacing options to fine-tune the layout and prevent overlap or crowding</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Google Docs offers several flexible ways to write and manage math equations:</p>
<ul>
<li><p><strong>Use the built-in equation editor</strong> for basic symbols, fractions, exponents, and common operations. It’s easy to access and great for straightforward math tasks without needing special syntax.</p>
</li>
<li><p><strong>Try LaTeX-like commands</strong> inside the equation editor for faster input. You can type commands like <code>\frac</code>, <code>\sqrt</code>, or <code>\alpha</code> to quickly insert structured equations without navigating menus.</p>
</li>
<li><p><strong>Install add-ons like Auto-LaTeX Equations</strong> for advanced LaTeX rendering. This is especially useful if you're copying equations from Overleaf, ChatGPT, or LaTeX documents into Google Docs, as it preserves formatting and converts code into clean equation images.</p>
</li>
<li><p><strong>Use external tools when copying from other formats</strong>, like the <em>ChatGPT to Google Docs or PDF</em> Chrome extension, which helps retain equation formatting when moving content from ChatGPT or other platforms.</p>
</li>
</ul>
<p>Whether you’re completing math homework, preparing teaching materials, or writing a research paper, Google Docs, combined with these tools, gives you everything you need to create clear, professional-looking documents with math content.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Merge Multiple Google Docs into One ]]>
                </title>
                <description>
                    <![CDATA[ Merging multiple Google Docs into a single document is often essential for compiling reports, gathering information from various sources, or creating unified documents for presentations or sharing. By combining multiple files into one, users can keep... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/merge-multiple-google-docs-with-apps-script-or-google-docs-api/</link>
                <guid isPermaLink="false">672103feae01d783da13018b</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ merging ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikram Aruchamy ]]>
                </dc:creator>
                <pubDate>Tue, 29 Oct 2024 15:49:18 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730115525086/d5d63d7d-a5c0-4e16-868c-50901aebb248.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Merging multiple Google Docs into a single document is often essential for compiling reports, gathering information from various sources, or creating unified documents for presentations or sharing.</p>
<p>By combining multiple files into one, users can keep information organized, streamline collaboration, and simplify document handling for larger projects or recurring tasks.</p>
<p>But Google Docs lacks a built-in feature for merging multiple documents. This can make this process time-consuming if you’re trying to do it manually.</p>
<p>While there are add-ons available for <a target="_blank" href="https://workspace.google.com/marketplace/app/merge_docs_pro/61337277026">merging multiple Google Docs into one</a>, you can also create your own scripts using Google Apps Script or the Google Docs API for customized solutions. This approach gives you greater flexibility, letting you set up recurring document consolidation and manage high volumes of merges tailored to your specific needs.</p>
<p>In this tutorial, I’ll explain how to merge multiple Google Docs into one document using <a target="_blank" href="https://developers.google.com/apps-script">Apps Script</a> or the <a target="_blank" href="https://developers.google.com/docs/api/reference/rest">Google Docs API</a>.</p>
<h2 id="heading-how-to-merge-google-docs-using-google-apps-script">How to Merge Google Docs Using Google Apps Script</h2>
<p>Using Google Apps Script to merge multiple Google Docs is a straightforward way to automate document merging directly within Google Workspace.</p>
<p>This approach should work well for you if you need a simple solution that doesn’t require complex setups or external APIs. You can run Apps Script within Google Drive, making it easy to set up and execute directly from the browser.</p>
<p>Below is a step-by-step guide on how to use Google Apps Script for merging documents.</p>
<h3 id="heading-step-1-open-google-apps-script"><strong>Step 1: Open Google Apps Script</strong></h3>
<p>In Google Drive, click on <strong>New</strong> &gt; <strong>Google Apps Script</strong> to create a new script.</p>
<p>Then name the project something relevant, like “Document Merger.”</p>
<h3 id="heading-step-2-write-the-apps-script-code"><strong>Step 2: Write the Apps Script Code</strong></h3>
<p>Copy and paste the following code into the Apps Script editor. This script will create a new Google Doc and append content from each specified document.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mergeGoogleDocs</span>(<span class="hljs-params">docIds</span>) </span>{
  <span class="hljs-keyword">const</span> mergedDoc = DocumentApp.create(<span class="hljs-string">"Merged Document"</span>); <span class="hljs-comment">// Creates a new document</span>
  <span class="hljs-keyword">const</span> body = mergedDoc.getBody();

  docIds.forEach(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> doc = DocumentApp.openById(id);
    <span class="hljs-keyword">const</span> docBody = doc.getBody();

    <span class="hljs-comment">// Append content of each document to the merged document</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; docBody.getNumChildren(); i++) {
      <span class="hljs-keyword">const</span> element = docBody.getChild(i).copy(); <span class="hljs-comment">// Copy each element to preserve formatting</span>
      body.appendParagraph(element.getText());
    }
    body.appendPageBreak(); <span class="hljs-comment">// Add a page break after each document</span>
  });

  Logger.log(<span class="hljs-string">"Merged Document URL: "</span> + mergedDoc.getUrl());
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">runMerge</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> docIds = [
    <span class="hljs-string">'DOCUMENT_ID_1'</span>, 
    <span class="hljs-string">'DOCUMENT_ID_2'</span>, 
    <span class="hljs-string">'DOCUMENT_ID_3'</span>
  ]; <span class="hljs-comment">// Replace with your actual document IDs</span>

  mergeGoogleDocs(docIds);
}
</code></pre>
<p><strong>Explanation of the Code:</strong></p>
<ul>
<li><p><strong>Creating the Merged Document</strong>: <code>DocumentApp.create("Merged Document")</code> creates a new Google Doc named "Merged Document," which will serve as the destination for all the content.</p>
</li>
<li><p><strong>Retrieving and Copying Content</strong>: <code>DocumentApp.openById(id)</code> opens each document in <code>docIds</code>, then retrieves its body content. The script copies each element, preserving its original formatting, and appends it to the new document.</p>
</li>
<li><p><strong>Adding Page Breaks</strong>: <code>body.appendPageBreak()</code> adds a page break after each document, helping maintain a clear separation between merged sections.</p>
</li>
<li><p><strong>Logging the Merged Document URL</strong>: The final URL of the merged document is logged, allowing you to access it directly from the Apps Script console.</p>
</li>
</ul>
<h3 id="heading-step-3-run-the-script"><strong>Step 3: Run the Script</strong></h3>
<p>First, you’ll want to save the script and authorize any required permissions.</p>
<p>Then in the Apps Script editor, select <code>runMerge()</code> as the function to run. Enter an array of document IDs you want to merge, like <code>['DOCUMENT_ID_1', 'DOCUMENT_ID_2', 'DOCUMENT_ID_3']</code>.</p>
<p>Finally, run the script, and it will create a merged document in your Google Drive. The URL will display in the console log.</p>
<h3 id="heading-how-to-customize-the-script"><strong>How to Customize the Script</strong></h3>
<p><strong>Order of Documents</strong>: The sequence in which documents are merged is controlled by the order of <code>docIds</code> in the array. Arrange these document IDs to define the exact order you want in the final document.</p>
<p>This approach is useful for structuring documents such as reports, books, or presentations, ensuring that chapters or sections appear in the intended flow.</p>
<p><strong>Adding Custom Formatting</strong>: The script can be customized to add specific formatting to each section of the merged document. You can insert headers or footers to distinguish each document, include page breaks, or set up consistent styling for fonts, sizes, and colors.</p>
<p>For example, you can add headers programmatically at the start of each new document in the merge, helping create a cohesive structure.</p>
<p><strong>Handling Specific Elements</strong>: Apps Script supports detailed customization to merge only certain types of content, like text, images, or tables, while skipping others. You can adjust the script to filter out elements by type or to prioritize specific formats.</p>
<p>For instance, to create a visually appealing document, you might choose to merge only text and images while excluding tables or unsupported elements. This approach provides a more polished final document by focusing on the content types you need most.</p>
<h3 id="heading-when-to-use-google-apps-script-for-merging"><strong>When to Use Google Apps Script for Merging</strong></h3>
<p>Google Apps Script is ideal if you want a simple, in-drive solution without needing to set up external API access. It’s especially useful for quick merges or individual projects within Google Workspace, and it provides enough flexibility to handle most standard document formats and structures.</p>
<p>For more complex requirements, such as merging across other platforms or integrating with external tools, consider using the Google Docs API explained in the next section.</p>
<h2 id="heading-how-to-merge-google-docs-using-the-google-docs-api">How to Merge Google Docs Using the Google Docs API</h2>
<p>Combining Google Docs using the Google Docs API allows you to programmatically combine content from multiple documents into one unified file. This is ideal for automating repetitive merges or creating customized documents on demand.</p>
<p>This approach is powerful for users who need precise control over document content, formatting, and layout, making it suitable for larger workflows or integrations within other applications.</p>
<p>Below is a detailed, step-by-step guide on how to use the Google Docs API to merge multiple Google Docs into one.</p>
<h3 id="heading-step-1-enable-the-google-docs-api"><strong>Step 1: Enable the Google Docs API</strong></h3>
<p>First, go to the <a target="_blank" href="https://console.cloud.google.com/">Google Cloud Console</a>. Create a new project or select an existing one.</p>
<p>In the API Library, search for "Google Docs API" and enable it for your project.</p>
<p>Next, create OAuth 2.0 credentials by going to <strong>APIs &amp; Services</strong> &gt; <strong>Credentials</strong>. Choose <strong>Create Credentials</strong> &gt; <strong>OAuth client ID</strong> and configure this for a Web Application if you plan to integrate it into Web services.</p>
<h3 id="heading-step-2-install-the-googleapis-client-library"><strong>Step 2: Install the</strong> <code>googleapis</code> <strong>Client Library</strong></h3>
<p>In a Node.js environment, you’ll need the <code>googleapis</code> package to interact with the Google Docs API. Install it by running:</p>
<pre><code class="lang-bash">npm install googleapis
</code></pre>
<h3 id="heading-step-3-write-the-script-to-merge-google-docs"><strong>Step 3: Write the Script to Merge Google Docs</strong></h3>
<p>The following script uses the Google Docs API to create a new document, retrieve content from each source document, and then append this content to the new document.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { google } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'googleapis'</span>);
<span class="hljs-keyword">const</span> docs = google.docs(<span class="hljs-string">'v1'</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mergeGoogleDocs</span>(<span class="hljs-params">auth, docIds</span>) </span>{
  <span class="hljs-comment">// Step 3a: Create a new document that will serve as the merged document</span>
  <span class="hljs-keyword">const</span> newDoc = <span class="hljs-keyword">await</span> docs.documents.create({
    auth,
    <span class="hljs-attr">requestBody</span>: { <span class="hljs-attr">title</span>: <span class="hljs-string">'Merged Document'</span> },
  });
  <span class="hljs-keyword">const</span> newDocId = newDoc.data.documentId;

  <span class="hljs-comment">// Step 3b: Loop through each document ID, retrieving content and appending it to the new document</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> docId <span class="hljs-keyword">of</span> docIds) {
    <span class="hljs-comment">// Retrieve the document's body content</span>
    <span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> docs.documents.get({
      auth,
      <span class="hljs-attr">documentId</span>: docId,
    });

    <span class="hljs-comment">// Prepare each content element as a request for the new document</span>
    <span class="hljs-keyword">const</span> requests = doc.data.body.content.map(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> ({
      <span class="hljs-attr">insertText</span>: {
        <span class="hljs-attr">text</span>: element.paragraph?.elements?.[<span class="hljs-number">0</span>]?.textRun?.content || <span class="hljs-string">''</span>,
        <span class="hljs-attr">location</span>: { <span class="hljs-attr">index</span>: <span class="hljs-number">1</span> }, <span class="hljs-comment">// Append to the start of the document, shift with each insertion</span>
      },
    }));

    <span class="hljs-comment">// Send a batch update request to insert all elements into the new document</span>
    <span class="hljs-keyword">await</span> docs.documents.batchUpdate({
      auth,
      <span class="hljs-attr">documentId</span>: newDocId,
      <span class="hljs-attr">requestBody</span>: { requests },
    });
  }

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Merged Document URL: https://docs.google.com/document/d/<span class="hljs-subst">${newDocId}</span>`</span>);
}
</code></pre>
<p><strong>Explanation of the Code:</strong></p>
<ol>
<li><p><strong>Creating the Merged Document</strong>: <code>docs.documents.create()</code> creates a new Google Doc titled "Merged Document." This document ID (<code>newDocId</code>) will serve as the destination where content from each document is appended.</p>
</li>
<li><p><strong>Retrieving Content</strong>: The <code>docs.documents.get()</code> method fetches each document’s content based on its ID. This retrieves all elements from the document body, such as paragraphs, images, and other supported elements.</p>
</li>
<li><p><strong>Preparing Insert Requests</strong>: The <code>map()</code> function converts each document element into an <code>insertText</code> request. Each request specifies the text and the location in the new document where it should be added.</p>
</li>
<li><p><strong>Appending Text in Sequence</strong>: The <code>batchUpdate</code> method takes a set of requests and applies them sequentially to the new document. Here, the location index starts at 1 (the beginning of the document) and shifts with each new insertion to prevent overwriting.</p>
</li>
</ol>
<h3 id="heading-step-4-run-the-script"><strong>Step 4: Run the Script</strong></h3>
<p>Now you’ll initialize the <code>auth</code> variable with <a target="_blank" href="https://developers.google.com/identity/protocols/oauth2">OAuth 2.0 credentials</a>, which authenticates access to the Docs API.</p>
<p>Then you’ll need to call the <code>mergeGoogleDocs</code> function, passing the <code>auth</code> object and an array of document IDs.</p>
<p>Once the script runs, it will output a URL for the merged document, which you can access directly in Google Docs.</p>
<h3 id="heading-customization-and-additional-options"><strong>Customization and Additional Options</strong></h3>
<ul>
<li><p><strong>Order of Insertion</strong>: Control the order in which document content is appended by arranging the document IDs in <code>docIds</code>.</p>
</li>
<li><p><strong>Formatting</strong>: The Google Docs API can support additional formatting, such as bold or italic text, by modifying the insert requests. This can be achieved with advanced requests using the <code>updateTextStyle</code> API method.</p>
</li>
<li><p><strong>Element Types</strong>: The script currently handles only text paragraphs. To merge other elements like images or tables, extend the script to support more element types by using conditional checks on the <code>element</code> structure.</p>
</li>
</ul>
<h3 id="heading-when-to-use-google-docs-api-for-merging"><strong>When to Use Google Docs API for Merging</strong></h3>
<p>The Google Docs API is ideal if you need precise control over document structure, element-specific formatting, and larger-scale automation for merging.</p>
<p>This approach is especially useful when handling complex formatting requirements, such as custom headers, lists, or tables, and allows for seamless integration with external applications or workflows outside Google Workspace.</p>
<p>If you have high-volume merge needs or you’re looking to incorporate merging into broader, automated processes, the Google Docs API provides advanced flexibility and customization options beyond what Google Apps Script can offer.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, merging Google Docs is crucial for organizing and streamlining document management. While Google Docs lacks a built-in feature for this, you can leverage Google Apps Script for straightforward automation or the Google Docs API for more advanced, large-scale merging.</p>
<p>For those seeking a user-friendly solution without the need for coding, <a target="_blank" href="https://www.mergedocs.pro/"><strong>Merge Docs Pro</strong></a> provides an intuitive interface to combine multiple Google Docs into one document. It simplifies document consolidation, enhances collaboration, and saves time, making it an excellent choice if you’re looking to streamline your workflow within Google Workspace.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Pandoc – An Open Source Tool for Technical Writers ]]>
                </title>
                <description>
                    <![CDATA[ Technical writers frequently navigate the complexities of various document formats and revisions. Pandoc, a free and open-source tool, offers a powerful solution to streamline these processes. In this tutorial, I'll explain the Pandoc's functionaliti... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-pandoc/</link>
                <guid isPermaLink="false">66bb8ac7d2bda3e431549198</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ markdown ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technical writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikram Aruchamy ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jul 2024 15:33:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/pandoc-freecodecamp-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Technical writers frequently navigate the complexities of various document formats and revisions. <a target="_blank" href="https://pandoc.org/">Pandoc</a>, a free and open-source tool, offers a powerful solution to streamline these processes.</p>
<p>In this tutorial, I'll explain the Pandoc's functionalities, specifically focusing on two key areas that can significantly enhance the workflow for technical writers:</p>
<p><strong>Docs and Markdown Conversions</strong>: If you write in Google Docs to leverage their collaborative writing, editing, and review features, Pandoc empowers you to <a target="_blank" href="https://www.docstomarkdown.pro/convert-google-docs-to-markdown/">convert Google Docs into markdown</a> for publishing needs, and if you write in markdown, it helps you convert markdown to Google Docs or Microsoft Word for creating deliverables.</p>
<p><strong>Merging of Multiple Docs into One</strong>: If you work in the "content as component approach", Pandoc allows you to <a target="_blank" href="https://workspace.google.com/marketplace/app/merge_docs_pro/61337277026">merge multiple Google Docs into a single document</a> with a few commands for publishing needs.</p>
<p>You can also create scripts to automate these processes.</p>
<h2 id="heading-why-use-markdown-for-technical-writing">Why Use Markdown for Technical Writing?</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/markdown-cheatsheet/">Markdown</a> is great for technical writers because it simplifies the writing process and improves collaboration. Here's why:</p>
<p><strong>Readability and Ease of Use</strong>: Markdown uses plain text symbols for formatting, making it clear and easy to learn. This lets you concentrate on writing clear content without getting caught up in styling complexities.</p>
<p><strong>Platform Independence</strong>: Markdown files are plain text, allowing you to write in any text editor on any device. This flexibility provides freedom in your writing environment and eliminates software compatibility concerns.</p>
<p><strong>Seamless Conversion with Free Tools</strong>: Free tools such as Pandoc offer format flexibility for markdown users, such as <a target="_blank" href="https://www.docstomarkdown.pro/convert-markdown-to-google-docs/">converting markdown to Google Docs</a>, Word documents, or HTML, ensuring compatibility with collaborative editing needs and final deliverables. This also extends to modern workflows, where large language models generate content in markdown. You can use ChatGPT or the Gemini API for creating initial drafts, integrate them with your writing, and then use Pandoc to convert the final document to Google Docs or Microsoft Word for team editing, feedback, and creating deliverables. This streamlined workflow empowers efficient and collaborative content creation.</p>
<p><strong>Version Control Friendly</strong>: Markdown's plain text nature enables seamless integration with version control systems like Git. This facilitates tracking changes, reverting to previous versions. This is particularly valuable for technical writing projects that often undergo revisions and involve multiple team members working on different sections.</p>
<h2 id="heading-why-merge-multiple-documents-into-one">Why Merge Multiple Documents into One?</h2>
<p>Technical writing often involves creating complex documents from smaller, reusable pieces. We call these pieces "content components." These components can be individual chapters, user guides, reference articles, or any other modular unit that contributes to the final product. In other words, content components are building blocks for bigger projects.</p>
<p>However, writing tools such as <a target="_blank" href="https://www.google.com/docs/about/">Google Docs</a> lack the ability to merge these components into a one document. This can be a major hurdle for projects like:</p>
<ol>
<li><strong>Technical Documentation:</strong> Building a user guide by assembling and reordering pre-written topics rather than crafting the entire document from scratch.</li>
<li><strong>Reference Guides:</strong> Consolidating multiple articles from a knowledge base into a single, printable reference manual.</li>
<li><strong>Book Authoring:</strong> Constructing a book by compiling individual chapters and appendices, streamlining the writing and editing process.</li>
</ol>
<p>In all these scenarios, the need to merge content components becomes crucial for creating well-structured and efficient documentation.</p>
<h2 id="heading-how-to-install-pandoc">How to Install Pandoc</h2>
<p>You can install Pandoc on your system using the packages available in the <a target="_blank" href="https://github.com/jgm/pandoc/releases">releases</a> list. The <a target="_blank" href="https://pandoc.org/installing.html">installation page</a> has a detailed tutorial on the steps to install it on different systems.</p>
<p>Once Pandoc is installed, you can use it in the command line to perform different document conversion operations as explained below.</p>
<h2 id="heading-how-to-convert-markdown-to-word-or-google-docs">How to Convert Markdown to Word or Google Docs</h2>
<p>To convert a markdown file to a Word document or Google Docs using Pandoc, follow these steps:</p>
<ol>
<li>Open a terminal or command prompt and navigate to the directory where your markdown file is located.</li>
<li>Run the following Pandoc command to convert your markdown file to a Word document:</li>
</ol>
<pre><code>pandoc input.md -o output.docx
</code></pre><p>Replace <code>input.md</code> with the name of your input markdown file, and <code>output.docx</code> with the desired name of your Word document.</p>
<p>To convert the Docx format into Google Docs, you can upload it to Google Drive and open it in Google Docs.</p>
<p>With these steps, you can convert your markdown files to Word documents or Google Docs using Pandoc.</p>
<h2 id="heading-how-to-convert-google-docs-or-word-to-markdown">How to Convert Google Docs or Word to Markdown</h2>
<p>In this section, I'll explain how to convert a Google Docs or Microsoft Word document into arkdown format.</p>
<p>While the Docs format is accepted by Pandoc, you cannot use the Google Docs URL directly with Pandoc. Therefore, you need to export the Google Doc into Docx format.</p>
<p>Go to <em>File</em> &gt; <em>Download</em> &gt; <em>Microsoft Word (.docx)</em> in your Google Doc to download the document in the <code>.docx</code> format as shown in the following image:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-08-at-3.05.41-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>option to download document in .docx format</em></p>
<p>Now you'll have the Word document equivalent of the Google Docs.</p>
<p>To <a target="_blank" href="https://www.docstomarkdown.pro/convert-word-to-markdown/">convert the Word document to markdown</a> using Pandoc, run the following command in your terminal or command prompt:</p>
<pre><code>pandoc input.docx -o output.md
</code></pre><p>Replace <code>input.docx</code> with the name of your Word document, and <code>output.md</code> with the desired name of your markdown file.</p>
<h2 id="heading-how-to-merge-multiple-documents-into-one">How to Merge Multiple Documents into One</h2>
<p>To <a target="_blank" href="https://www.mergedocs.pro/">merge multiple Google Docs or Word documents into a single file</a> using Pandoc, you can follow these two steps:</p>
<ol>
<li>Convert individual documents to markdown using the Pandoc conversion command to convert each Google Doc or Word document into a separate markdown file (explained in the previous section).</li>
<li>Once you have individual markdown files, use the following Pandoc command to merge them into a single document.</li>
</ol>
<pre><code>pandoc file1.md file2.md -o merged_output.docx
</code></pre><p>Replace <code>file1.md</code> and <code>file2.md</code> with the names of your input markdown files. These files will be merged into one <code>merged_output.docx</code>.</p>
<p>You can use your desired output format instead of <code>merged_output.docx</code> based on your goals. For instance, you can create a single HTML file if you intend to publish it on the web, or use the markdown format if your publishing platform supports markdown.</p>
<p>This approach leverages Pandoc's strengths for format conversion and merging to achieve the desired outcome of a unified document.</p>
<p>For more information and helpful answers about using Pandoc, check out the <a target="_blank" href="https://pandoc.org/faqs.html">Pandoc FAQs</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Pandoc is a powerful and versatile tool for technical writers, offering document conversion and merging capabilities. </p>
<p>With its ability to convert Google Docs into markdown and merge multiple documents into one, Pandoc streamlines the process of creating and publishing technical documentation.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Publish Google Docs to WordPress in an SEO-Optimized Way ]]>
                </title>
                <description>
                    <![CDATA[ WordPress is a popular content management system (CMS) known for its flexibility and user-friendly interface. But its built-in editor is not ideal for collaborative editing. Many publishers who work with writers need collaborative writing and editing... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/publish-google-docs-to-wordpress/</link>
                <guid isPermaLink="false">66bb8acb6b3bd8d6bf25ae4c</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SEO ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikram Aruchamy ]]>
                </dc:creator>
                <pubDate>Mon, 26 Feb 2024 23:21:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/fcc-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>WordPress is a popular content management system (CMS) known for its flexibility and user-friendly interface. But its built-in editor is not ideal for collaborative editing.</p>
<p>Many publishers who work with writers need collaborative writing and editing features. This is where Google Docs comes into the picture. It’s a collaborative platform, enabling multiple users to write and edit simultaneously. </p>
<p>Google Docs also offers powerful formatting tools, simplifying the content creation process before transferring it to WordPress for publishing.</p>
<p>However, <a target="_blank" href="https://www.docstowp.pro/">converting Google Docs to WordPress</a> can add an extra step to your publishing workflow and requires some attention to detail.</p>
<p>This tutorial explores four seamless methods to bridge that gap and streamline your publishing journey:</p>
<ul>
<li>Manually converting using the copy-paste method</li>
<li>Publishing with SEO optimization using the <a target="_blank" href="https://workspace.google.com/marketplace/app/docs_to_wp_pro/346830534164">Docs to WP Pro</a> add-on</li>
<li>Using the WordPress Gutenberg editor </li>
<li>Using the Markdown conversion method</li>
</ul>
<h2 id="heading-using-the-simple-copy-paste-method">Using the Simple Copy Paste Method</h2>
<p>In this simple copy-paste approach, you can copy the contents from Google Docs and navigate to WordPress to create a new post, then paste in the content.</p>
<p>But when pasting content into WordPress, you may encounter some issues that require manual adjustments, especially if your WordPress site is using the Classic Editor.</p>
<p>First of all, you may have issues with spacing – for example, WordPress adds extra line breaks, as you can see in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-145.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unnecessary link breaks added by Wordpress</em></p>
<p>Second, you may have to remove or clean up messy code – WordPress adds unnecessary span tags to the content.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-144.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unnecessary span tags</em></p>
<p>Finally, you may have to manually upload images to the Media library and include them in your posts, as it's not done automatically.</p>
<p>The spacing issues and the messy code can <a target="_blank" href="https://www.cloudflare.com/en-in/learning/performance/how-website-speed-boosts-seo/">affect your website performance</a>. HTML counts toward your overall page weight, so unnecessary code slows your page down, impacting both user experience and SEO. </p>
<p>Images also need to be manually compressed before uploading to the WordPress Media library.</p>
<p>Also, the native Google Docs doesn’t offer options for SEO optimization or the use of reusable blocks to add boilerplate content. So using this method requires more manual work for publishing from Google Docs to WordPress. </p>
<h2 id="heading-using-docs-to-wp-pro-add-on">Using Docs to WP Pro add-on</h2>
<p>The Google Docs add-on Docs to WP Pro can help you publish SEO-optimized posts from Google Docs to WordPress.</p>
<p><a href="https://workspace.google.com/marketplace/app/docs_to_wp_pro/346830534164?pann=b" target="_blank"><img src="https://workspace.google.com/static/img/marketplace/en/gwmBadge.svg?" alt="My image" width="600" height="400" loading="lazy"></a></p>
<p>The add-on allows you to configure the site once and includes additional capabilities, such as letting you create reusable blocks for content like <em>FAQs</em>, <em>Author bios</em>, and <em>affiliate disclaimers</em>. Beyond these, the add-on provides the following functionalities:</p>
<h3 id="heading-automated-internal-linking">Automated Internal Linking</h3>
<p>Adding <a target="_blank" href="https://ahrefs.com/seo/glossary/internal-link">internal links</a> to your article is crucial for enhancing user experience and SEO. After creating content, identifying potential keywords and adding relevant internal links is essential.</p>
<p>But manually managing this process can be challenging, especially with a large number of articles and multiple authors. It becomes difficult to identify all potentially related articles without a comprehensive overview of your site, leading to more guesswork.</p>
<p>The Docs to WP Pro add-on can automate internal linking by automatically identifying and linking relevant keywords within your content to related posts on your site. This saves you time and effort and can help improve the SEO of your content by creating relevant internal links.</p>
<h3 id="heading-related-posts-suggestions">Related Posts Suggestions</h3>
<p>Including a few related posts at the end of articles enhances reader engagement, increases <a target="_blank" href="https://www.semrush.com/blog/dwell-time/">dwell time</a>, and improves overall user experience.</p>
<p>For this use case, the tool suggests topics that can be added as <em>related posts</em>. These suggestions include additional contextual data for the target posts, such as <em>Relevance score</em>, <em>Number of incoming links</em>, <em>Post published on</em>, and <em>Post update on</em>.</p>
<p>This information helps you link to the most recent articles when you have multiple articles on closely related topics and ensures a balanced distribution of internal links.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-146.png" alt="Image" width="600" height="400" loading="lazy">
<em>Suggestions for Related posts</em></p>
<h3 id="heading-seo-optimization">SEO Optimization</h3>
<p>Apart from internal linking, the tool also supports other <a target="_blank" href="https://www.freecodecamp.org/news/wordpress-seo/">SEO optimizations</a> and seamlessly integrates with RankMath and Yoast.</p>
<p>The tool allows you to add a focus keyword and checks the content against it, suggesting optimizations such as the presence of the focus keyword in the title, subheadings, and image alt text. </p>
<p>The tool also evaluates whether the keyword is naturally integrated into the content or if it is overly used.</p>
<p>Additionally, the add-on provides useful information such as Flesch reading scores, content length, and reading time, helping you improve the readability of your content.</p>
<h3 id="heading-image-handling">Image Handling</h3>
<p>The add-on offers effortless image handling by automatically <a target="_blank" href="https://www.freecodecamp.org/news/image-optimization-558d9f449e3/">compressing images</a> before publishing to the WordPress media library. This ensures a sleek media library and enhances your site's loading time.</p>
<p>It also enables you to add featured images directly from Google Docs to your WordPress posts. It can also automatically generate Alt Text for your images, contributing to improved accessibility and SEO.</p>
<p>The add on has a free version with paid features. </p>
<h2 id="heading-using-the-wordpress-gutenberg-editor">Using the WordPress Gutenberg Editor</h2>
<p>Another option for publishing Google Docs to WordPress without additional add-ons is the WordPress Gutenberg editor. When you paste the Google Docs content into the <a target="_blank" href="https://www.wpbeginner.com/beginners-guide/how-to-use-the-new-wordpress-block-editor/">Gutenberg editor</a>, you won't encounter formatting issues such as extra line breaks or span tags.</p>
<p>This proves helpful when your content doesn't include images. But if your content contains images, the Gutenberg editor presents a few challenges. </p>
<p>After pasting the content into WordPress, checking the HTML code reveals that the image source is set to the location of the image in your Google Drive. This implies that you are hosting the images through your personal Google Drive, which is not recommended from a security standpoint.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-147.png" alt="Image" width="600" height="400" loading="lazy">
<em>Images hosted from your Google account</em></p>
<p>Also, deleting the image from your Google Drive or the Google Docs containing the image will result in the image disappearing from your website. This means you have to check your entire website and delete any links of images from your Google Drive.</p>
<p>An alternative approach is to upload the images manually to your WordPress media library and use those images in your posts. This adds some manual work and is error-prone. Also, the images must be manually compressed before uploading to the media library.</p>
<h2 id="heading-markdown-conversion-method">Markdown Conversion Method</h2>
<p>You can <a target="_blank" href="https://www.docstomarkdown.pro/">convert Google Docs to Markdown</a> format using the free and open source add on <a target="_blank" href="https://workspace.google.com/marketplace/app/docs_to_markdown/700168918607">Docs to Markdown</a>. The free tool will convert your fully formatted Google Doc to Markdown format (.md). You can paste this Markdown text into your WordPress editor for perfectly formatted text without any additional line breaks or span tags.</p>
<p>This option is also most useful <em>only</em> if your content doesn't include images. If your content does have images, it requires manual work to compress and upload your images into your WordPress media library and update the HTML accordingly.</p>
<p>Also, this method doesn't include built-in SEO features.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Transferring content from Google Docs to WordPress efficiently is essential for a smooth workflow. </p>
<p>This tutorial has presented four methods: manual copy-paste, using the Docs to WP Pro add-on, using WordPress Gutenberg editor and Markdown conversion method. </p>
<p>Each method has its own advantages and disadvantages, so the best choice for you will depend on your specific needs and preferences.</p>
<ul>
<li><strong>Manual copy-paste</strong> is a simple option but requires manual adjustments for formatting and images.</li>
<li><strong>Docs to WP Pro</strong> offers features like automated internal linking, SEO optimizations and image handling, but may require additional investment.</li>
<li><strong>WordPress Gutenberg editor</strong> is a best option for the text only posts, but if you have images, then it requires additional work to host your images on WordPress media library. </li>
<li><strong>Converting to Markdown</strong> preserves formatting but requires manual image handling and lacks SEO optimization features.</li>
</ul>
<p>Consider factors like the amount of content you create, your budget, and your technical expertise when making your decision.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Google Docs Clone with React, Material UI, & Firebase ]]>
                </title>
                <description>
                    <![CDATA[ By Nishant Kumar In this article, we'll build a Google Docs clone using React, Material UI, and Firebase. The final app will look like this: If we click any document, it will open up and we can edit them however we need to. And the most amazing fea... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-google-docs-clone-with-react-and-firebase/</link>
                <guid isPermaLink="false">66d460487df3a1f32ee7f875</guid>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 09 May 2022 21:16:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/How-to-Build-a-Weather-Application-using-React--11-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nishant Kumar</p>
<p>In this article, we'll build a Google Docs clone using React, Material UI, and Firebase.</p>
<p>The final app will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-145537.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If we click any document, it will open up and we can edit them however we need to.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-145643.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And the most amazing feature is that we can edit a document in real time. This means that if two people are working on the same document, their progress will be reflected in both instances.</p>
<p>But before we start, make sure you have Node installed in your system. If not, go to <a target="_blank" href="https://nodejs.org/en/download/">https://nodejs.org/en/download/</a> to download and install it.</p>
<p>If you'd like to follow along in video format, here's this tutorial on my YouTube channel:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/7ZnjKIYVJsE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-basic-project-setup">Basic Project Setup</h2>
<p>Let's first create a React app using the below command:</p>
<pre><code>npx create-react-app google-docs-clone
</code></pre><p>This will install all the packages and dependencies into a local folder.</p>
<p>Then, simply navigate into the project folder and run <strong>npm start</strong> to run the app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-105724.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will see all these code here that we need to remove. We will start with a blank canvas.</p>
<p>Next create a folder called components. Inside that folder, let's create a file called <strong>docs.js</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-110011.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Make this component a functional component, like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Docs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>docs<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Now, import this file into the main <strong>App.js</strong> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Docs <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/docs'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Docs</span> /&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>And we'll see this output on the screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-110713.png" alt="Image" width="600" height="400" loading="lazy">
<em>Google docs clone showing output "docs" in upper left corner</em></p>
<p>Now, let's make the title appear in the center. So in docs.js, give the main <strong>div</strong> a className of <strong>docs-main</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Docs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'docs-main'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Docs Clone<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>And in <strong>App.css</strong> file, add the following styles:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.docs-main</span>{
    <span class="hljs-attribute">text-align</span>: center;
}
</code></pre>
<p>Now our app looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-113002.png" alt="Image" width="600" height="400" loading="lazy">
<em>Google docs clone with title in center</em></p>
<p>Now, we need a button to add our documents. So, let's create it with this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Docs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'docs-main'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Docs Clone<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>&gt;</span>
            Add a Document
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>And the CSS looks like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.add-docs</span>{
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffc107</span>;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Let's import some fonts from Google Fonts. Place this at the top of the CSS file:</p>
<pre><code>@<span class="hljs-keyword">import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Poppins&amp;family=Roboto&amp;display=swap'</span>);
</code></pre><pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Poppins&amp;family=Roboto&amp;display=swap'</span>);

<span class="hljs-selector-class">.docs-main</span>{
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Roboto'</span>, sans-serif;
}

<span class="hljs-selector-class">.add-docs</span>{
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffc107</span>;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Poppins'</span>, sans-serif;
}
</code></pre>
<p>To add fonts, simply do this in the respective classNames.</p>
<h2 id="heading-how-to-install-material-ui">How to Install Material UI</h2>
<p>To install Material UI, simply type the command below. If you want to read the documentation, head over to <a target="_blank" href="https://mui.com/">https://mui.com/</a>.</p>
<pre><code>npm install @mui/material @emotion/react @emotion/styled
</code></pre><p>Now, let's create one more component for the modal. We'll use this modal to add documents to the Firebase database.  </p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Box <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Box'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Button'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Typography'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Modal'</span>;

<span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
    <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">transform</span>: <span class="hljs-string">'translate(-50%, -50%)'</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">400</span>,
    <span class="hljs-attr">bgcolor</span>: <span class="hljs-string">'background.paper'</span>,
    <span class="hljs-attr">border</span>: <span class="hljs-string">'2px solid #000'</span>,
    <span class="hljs-attr">boxShadow</span>: <span class="hljs-number">24</span>,
    <span class="hljs-attr">p</span>: <span class="hljs-number">4</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Modal</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [open, setOpen] = React.useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> handleOpen = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span>
                <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"modal-modal-title"</span>
                <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"modal-modal-description"</span>
            &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{style}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"modal-modal-title"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h2"</span>&gt;</span>
                        Text in a modal
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"modal-modal-description"</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">mt:</span> <span class="hljs-attr">2</span> }}&gt;</span>
                        Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>This is a simple modal component from Material UI. Now we have to import this component into our Docs.js component.</p>
<p>And we need to move a few things from Modal.js to Docs.js.</p>
<pre><code><span class="hljs-keyword">const</span> [open, setOpen] = React.useState(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> handleOpen = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">true</span>);
</code></pre><p>If we click the Add a Document button, the modal will open using these functions:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'./Modal'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Docs</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [open, setOpen] = React.useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> handleOpen = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'docs-main'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Docs Clone<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleOpen}</span>
            &gt;</span>
                Add a Document
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">setOpen</span>=<span class="hljs-string">{setOpen}</span>
            /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<p>So, pass these functions and states as props into the modal component and receive them.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Box <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Box'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Button'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Typography'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Modal'</span>;

<span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
    <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">transform</span>: <span class="hljs-string">'translate(-50%, -50%)'</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">400</span>,
    <span class="hljs-attr">bgcolor</span>: <span class="hljs-string">'background.paper'</span>,
    <span class="hljs-attr">border</span>: <span class="hljs-string">'2px solid #000'</span>,
    <span class="hljs-attr">boxShadow</span>: <span class="hljs-number">24</span>,
    <span class="hljs-attr">p</span>: <span class="hljs-number">4</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalComponent</span>(<span class="hljs-params">{
    open,
    setOpen,
}</span>) </span>{
    <span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span>
                <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"modal-modal-title"</span>
                <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"modal-modal-description"</span>
            &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{style}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"modal-modal-title"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h2"</span>&gt;</span>
                        Text in a modal
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"modal-modal-description"</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">mt:</span> <span class="hljs-attr">2</span> }}&gt;</span>
                        Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>Now, this is how our page looks with the modal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-115100.png" alt="Image" width="600" height="400" loading="lazy">
<em>Google docs clone page with model showing</em></p>
<p>Let's add an input in the Modal, for the filename.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span>
                <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"modal-modal-title"</span>
                <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"modal-modal-description"</span>
            &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{style}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Add the Title'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'add-input'</span>
                    /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>
</code></pre>
<p>Let's give it some styles with the following:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.add-input</span>{
    <span class="hljs-attribute">width</span>: <span class="hljs-number">95%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">outline</span>: none;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#676767</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Poppins'</span>, sans-serif;
}
</code></pre>
<p>And now, this is how our Modal looks:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-115756.png" alt="Image" width="600" height="400" loading="lazy">
<em>Modal with styling added</em></p>
<p>Let's also add a Button. We can copy the Add a Document Button.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Box <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Box'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Button'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Typography'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Modal'</span>;

<span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
    <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">transform</span>: <span class="hljs-string">'translate(-50%, -50%)'</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">500</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">150</span>,
    <span class="hljs-attr">bgcolor</span>: <span class="hljs-string">'background.paper'</span>,
    <span class="hljs-attr">boxShadow</span>: <span class="hljs-number">24</span>,
    <span class="hljs-attr">p</span>: <span class="hljs-number">5</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalComponent</span>(<span class="hljs-params">{
    open,
    setOpen,
}</span>) </span>{
    <span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span>
                <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"modal-modal-title"</span>
                <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"modal-modal-description"</span>
            &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{style}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Add the Title'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'add-input'</span>
                    /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'button-container'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>
                        &gt;</span>
                            Add
                        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>And the CSS looks like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.button-container</span>{
    <span class="hljs-attribute">text-align</span>: center;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">30px</span>;
}
</code></pre>
<p>This is how it looks now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-120129.png" alt="Image" width="600" height="400" loading="lazy">
<em>Modal with styling and button added</em></p>
<h2 id="heading-how-to-add-firebase-to-our-app">How to Add Firebase to Our App</h2>
<p>Now, let's install Firebase for the database. Simply install Firebase using the below command:</p>
<pre><code>npm install firebase
</code></pre><p>Head over to <a target="_blank" href="https://firebase.google.com/">https://firebase.google.com/</a> and click Go to console at the top right.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-120526.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then, click Add Project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-120625.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After creating the Project, click the code button to create a web app in Firebase. Give it a name and we are ready to go.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-120803.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we will add all these config data that we have to store in our React app. So, create a file called <strong>firebaseConfig.js</strong> and add them.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-120857.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We are going to need the database, so let's initalize it. Also, export the const app and database like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { initializeApp } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>;
<span class="hljs-keyword">import</span> { getFirestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-comment">//Your Firebase Data</span>
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> app = initializeApp(firebaseConfig);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> database = getFirestore(app)
</code></pre>
<p>Import the app and database into <strong>App.js</strong> file. And pass the database as props to the Docs component. We'll use it later to add data to Firebase Firestore.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Docs <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/docs'</span>;
<span class="hljs-keyword">import</span> { app, database } <span class="hljs-keyword">from</span> <span class="hljs-string">'./firebaseConfig'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Docs</span> <span class="hljs-attr">database</span>=<span class="hljs-string">{database}/</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>And in the Docs component. Also, let's receive the database export from props.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'./Modal'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Docs</span>(<span class="hljs-params">{
    database
}</span>) </span>{
    <span class="hljs-keyword">const</span> [open, setOpen] = React.useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> handleOpen = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'docs-main'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Docs Clone<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleOpen}</span>
            &gt;</span>
                Add a Document
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">setOpen</span>=<span class="hljs-string">{setOpen}</span>
            /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<p>Now, let's configure our Firestore Database. </p>
<p>Go to Firestore database from the left sidebar, and click Create Database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-121804.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will start our Database in Production Mode. So, click Next, and then Enable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-121900.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We have to make the security rules public, just for now. So, click Rules at the top tab and edit the following rules. This means that anyone can write data or read them, even without authentication.</p>
<pre><code class="lang-js">rules_version = <span class="hljs-string">'2'</span>;
service cloud.firestore {
  match /databases/{database}/documents {
    match /{<span class="hljs-built_in">document</span>=**} {
      allow read, write;
    }
  }
}
</code></pre>
<h2 id="heading-how-to-add-docs-data-to-the-firestore-database">How to Add Docs Data to the Firestore Database</h2>
<p>Now, let's actually add our data. But before that, we need to get the data from the input field.</p>
<p>So in the Docs component, create one state that will hold this data.</p>
<pre><code><span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>)
</code></pre><p>Pass the title and setTitle to the modal component.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">setOpen</span>=<span class="hljs-string">{setOpen}</span>
                <span class="hljs-attr">title</span>=<span class="hljs-string">{title}</span>
                <span class="hljs-attr">setTitle</span>=<span class="hljs-string">{setTitle}</span>
            /&gt;</span>
</code></pre>
<p>Receive them both as props, and set them in the input field.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Box <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Box'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Button'</span>;
<span class="hljs-keyword">import</span> Typography <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Typography'</span>;
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">'@mui/material/Modal'</span>;

<span class="hljs-keyword">const</span> style = {
    <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
    <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">left</span>: <span class="hljs-string">'50%'</span>,
    <span class="hljs-attr">transform</span>: <span class="hljs-string">'translate(-50%, -50%)'</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">500</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">150</span>,
    <span class="hljs-attr">bgcolor</span>: <span class="hljs-string">'background.paper'</span>,
    <span class="hljs-attr">boxShadow</span>: <span class="hljs-number">24</span>,
    <span class="hljs-attr">p</span>: <span class="hljs-number">5</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalComponent</span>(<span class="hljs-params">{
    open,
    setOpen,
    title, 
    setTitle
}</span>) </span>{
    <span class="hljs-keyword">const</span> handleClose = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">open</span>=<span class="hljs-string">{open}</span>
                <span class="hljs-attr">onClose</span>=<span class="hljs-string">{handleClose}</span>
                <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"modal-modal-title"</span>
                <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"modal-modal-description"</span>
            &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">sx</span>=<span class="hljs-string">{style}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Add the Title'</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">'add-input'</span>
                        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setTitle(event.target.value)}
                        value={title}
                    /&gt;
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'button-container'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>
                        &gt;</span>
                            Add
                        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>Now, if we type something in the input, it will be stored inside the <strong>title</strong> state.</p>
<p>Next, we need a function that will trigger the add data functions, so let's create it.</p>
<p>In Docs.js, create a function and pass it to the modal component:</p>
<pre><code><span class="hljs-keyword">const</span> addData = <span class="hljs-function">() =&gt;</span> {

}
</code></pre><p>Receive it in the modal component and simply bind it to the Add button like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'button-container'</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">'add-docs'</span>
                            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addData}</span>
                        &gt;</span>
                            Add
                        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now, the <strong>addData</strong> function will run when we click the Add button.</p>
<p>Now to send data from React to Firebase dynamically, let's import a few things from Firebase Firestore:</p>
<pre><code><span class="hljs-keyword">import</span> { addDoc, collection } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre><p>Here, we'll use <code>collection</code> to create a data collection in Firebase, and addDoc will add data to that collection.</p>
<p>Let's first create a collection reference. It will take the database that we got from the <strong>firebaseConfig.js</strong> and the name of the collection we want to use.</p>
<pre><code><span class="hljs-keyword">const</span> collectionRef = collection(database, <span class="hljs-string">'docsData'</span>)
</code></pre><p>Now, in the addData function, let's use <strong>addDoc</strong>. This <strong>addDoc</strong> function will take the collection reference, and the data itself.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addData = <span class="hljs-function">() =&gt;</span> {
        addDoc(collectionRef, {
            <span class="hljs-attr">title</span>: title
        })
        .then(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Data Added'</span>)
        })
        .catch(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Cannot add data'</span>)
        })
    }
</code></pre>
<p>Now, add something in the text input and click Add. It will be added into Firebase Firestore, with an alert that data has been added. But if it fails, we will get "Cannot add data."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-123810.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If we refresh the database, we'll see this new entry:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-07-123848.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And that's how we add data. Let's also close the modal after adding the data.</p>
<p>Create a function handleClose, and call this function right after the <strong>then</strong> block in the <strong>addData</strong> function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addData = <span class="hljs-function">() =&gt;</span> {
        addDoc(collectionRef, {
            <span class="hljs-attr">title</span>: title
        })
        .then(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Data Added'</span>);
            handleClose()
        })
        .catch(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Cannot add data'</span>)
        })
    }
</code></pre>
<h2 id="heading-how-to-read-the-data-from-firebase">How to Read the Data from Firebase</h2>
<p>Now, let's read the data that we added to Firebase. We will need the <strong>onSnapshot</strong> function for that. The onSnapshot function gets data in real time.</p>
<p>First, import it from Firebase like this:</p>
<pre><code><span class="hljs-keyword">import</span> { addDoc, collection, onSnapshot } <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre><p>Then, create a function <strong>getData</strong> that will get triggered when our page loads. So, we will put this onSnapshot into the React <strong>useEffect</strong> Hook.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
        onSnapshot(collectionRef, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(data.docs.map(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
                <span class="hljs-keyword">return</span> {...doc.data(), <span class="hljs-attr">id</span>: doc.id}
            }))
        })
    }
</code></pre>
<p>Then, call this function inside the useEffect Hook.</p>
<pre><code>useEffect(<span class="hljs-function">() =&gt;</span> {
        getData()
    }, [])
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-120757.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>But as you can see, the we are getting the data twice. That's because we are using React version 18, which includes <strong>concurrent rendering</strong>. That's why the useEffect hook will run twice.</p>
<p>To solve this, we need to create a <strong>useRef</strong> reference. </p>
<pre><code><span class="hljs-keyword">const</span> isMounted = useRef()
</code></pre><p>Then in the useEffect Hook, we have to check if isMounted.current is true. So, if it is true, we will return nothing. And then we will set isMounted.current to true, and we will then call our getData function.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span>(isMounted.current){
            <span class="hljs-keyword">return</span> 
        }

        isMounted.current = <span class="hljs-literal">true</span>;
        getData()
    }, [])
</code></pre>
<p>And if we now refresh the page, we will get the data only once.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-121500.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we have to include this data in an array state. So, let's do that.</p>
<p>Create a state of <strong>docsData</strong>.</p>
<pre><code> <span class="hljs-keyword">const</span> [docsData, setDocsData] = useState([]);
</code></pre><p>And set the incoming data inside this state using <strong>setDocsData</strong>.</p>
<pre><code><span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
        onSnapshot(collectionRef, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            setDocsData(data.docs.map(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
                <span class="hljs-keyword">return</span> {...doc.data(), <span class="hljs-attr">id</span>: doc.id}
            }))
        })
    }
</code></pre><p>Now, let's map our array for the data to show up in the UI.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                {docsData.map((doc) =&gt; {
                    return (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{doc.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    )
                })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This will display all the data in our React app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-121859.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will see both documents on our page. But let's make them appear in a grid. Give the div containers classNames of <strong>grid-main</strong> and <strong>grid-child</strong>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'grid-main'</span>&gt;</span>
                {docsData.map((doc) =&gt; {
                    return (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'grid-child'</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{doc.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    )
                })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>And in the CSS, add the following classes:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.grid-main</span>{
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">grid-template-columns</span>: auto auto auto auto;
    <span class="hljs-attribute">color</span>: whitesmoke;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.grid-child</span>{
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">98</span>, <span class="hljs-number">98</span>, <span class="hljs-number">98</span>);
    <span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Now, our app will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-122658.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-get-the-id-and-redirect-to-the-edit-docs-page">How to Get the ID and Redirect to the Edit Docs Page</h2>
<p>Now, each of these items above has an ID. We will use these IDs to redirect to another page where we can edit the items and write our main content. </p>
<p>For that, we need two packages. One is the React-Router to redirect us, and another is the React-Quill for our editor. Install them like this:</p>
<pre><code>npm i react-quill react-router-dom@<span class="hljs-number">6</span>
</code></pre><p>Now, let's configure routing to another page. But we need another page first. So, let's create it.</p>
<p>Create a component called <strong>EditDocs.</strong> Make it a functional component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EditDocs</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>EditDocs<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>To configure routing, come to <strong>index.js</strong>, the app's entry point. Wrap the  inside <strong>BrowserRouter</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">'./reportWebVitals'</span>;
<span class="hljs-keyword">import</span> { BrowserRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
root.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);

<span class="hljs-comment">// If you want to start measuring performance in your app, pass a function</span>
<span class="hljs-comment">// to log results (for example: reportWebVitals(console.log))</span>
<span class="hljs-comment">// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals</span>
reportWebVitals();
</code></pre>
<p>Now, we can use routing anywhere because we are declaring BrowserRouter at the basic level.</p>
<p>Now, come to the <strong>App.js</strong> file. Import Routes and Route from React-Router. We are also appending the ID in the <strong>editDocs path</strong>, so that we can see the id in the address bar.</p>
<pre><code><span class="hljs-keyword">import</span> { Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
</code></pre><pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> Docs <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/docs'</span>;
<span class="hljs-keyword">import</span> EditDocs <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/EditDocs'</span>;
<span class="hljs-keyword">import</span> { Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { app, database } <span class="hljs-keyword">from</span> <span class="hljs-string">'./firebaseConfig'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Docs</span> <span class="hljs-attr">database</span>=<span class="hljs-string">{database}</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/editDocs/:id"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">EditDocs</span> <span class="hljs-attr">database</span>=<span class="hljs-string">{database}/</span>&gt;</span>} /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>And add the following routes. If we go to <strong>'/editDocs/:id'</strong>, we will see our editDocs page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-124659.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we need to get the specific ID from the documents and send it to the editDocs page.</p>
<p>Create a function getID and assign the function to the documents.</p>
<pre><code><span class="hljs-keyword">const</span> getID = <span class="hljs-function">() =&gt;</span> {

}
</code></pre><pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'grid-main'</span>&gt;</span>
                {docsData.map((doc) =&gt; {
                    return (
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'grid-child'</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> getID(doc.id)}&gt;
                            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{doc.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    )
                })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now, if we click the document, we will get its ID if we log it in the console.</p>
<pre><code><span class="hljs-keyword">const</span> getID = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(id)
    }
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-124956.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, let's send this ID to the editDocs page using <strong>useNavigate</strong>.</p>
<p>First, import useNavigate from react-router.</p>
<pre><code><span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
</code></pre><p>Then, create an instance of useNavigate like this:</p>
<pre><code><span class="hljs-keyword">let</span> navigate = useNavigate();
</code></pre><p>Then, to pass the ID, simply do this. We will send ourselves to the editDocs page, along with the ID.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> getID = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
        navigate(<span class="hljs-string">`/editDocs/<span class="hljs-subst">${id}</span>`</span>)
}
</code></pre>
<p>Now, let's receive our ID at the other end. In the editDocs component, we need to <strong>useParams</strong> from react-router.</p>
<p>So, import it and create an instance:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">let</span> params = useParams();
</code></pre>
<p>Also if we console it, we will see the ID.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">let</span> params = useParams();
<span class="hljs-built_in">console</span>.log(params)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-125849.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can see that we get the ID in the address bar as well as the console.</p>
<p>Now, let's add <strong>React Quill</strong> to our editDocs page.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> ReactQuill <span class="hljs-keyword">from</span> <span class="hljs-string">'react-quill'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'react-quill/dist/quill.snow.css'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EditDocs</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> params = useParams();
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>EditDocs<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ReactQuill</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<p>We have to import React-Quill and the CSS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-131423.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>But we can see we have two toolbars here. To solve this, just remove <strong>React.StrictMode</strong> from <strong>index.js</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">'./reportWebVitals'</span>;
<span class="hljs-keyword">import</span> { BrowserRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
root.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
);

<span class="hljs-comment">// If you want to start measuring performance in your app, pass a function</span>
<span class="hljs-comment">// to log results (for example: reportWebVitals(console.log))</span>
<span class="hljs-comment">// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals</span>
reportWebVitals();
</code></pre>
<p>And we will be fine.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-131534.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we need a state for this React Quill data. So, let's create it. Also, we'll create a function to trigger when we type.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [docsDesc, setDocsDesc] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> getQuillData = <span class="hljs-function">() =&gt;</span> {

    }
</code></pre>
<p>Now, let's bind the function and the state to React Quill.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ReactQuill</span>
   <span class="hljs-attr">value</span>=<span class="hljs-string">{docsDesc}</span>
   <span class="hljs-attr">onChange</span>=<span class="hljs-string">{getQuillData}</span>
/&gt;</span>
</code></pre>
<p>In the <strong>getQuillData</strong> function, let's bind the value to the <strong>docsDesc</strong> state, using the <strong>setDocsDesc</strong> function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> getQuillData = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
        setDocsDesc(value)
    }
</code></pre>
<p>And we are done here. You can console this docsDesc state to check.</p>
<p>Now we have the ID, and the data that we can use to update the document. So, let's do that.</p>
<h2 id="heading-how-to-update-the-document">How to Update the Document</h2>
<p>We need two things, <strong>updateDoc</strong> and the <strong>collection</strong> function. We will use a Debounce function to call the updateDoc function. This means that when we finish typing, after 5 or 10 seconds, our updateDoc function will run. </p>
<p>So, let's create a function:</p>
<pre><code><span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-function">() =&gt;</span> {

}
</code></pre><p>We also need to specify the collection. For that, we need the <strong>database</strong> from <strong>App.js.</strong> So, let's get it using props.</p>
<pre><code>&lt;Route path=<span class="hljs-string">"/editDocs/:id"</span> element={<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">EditDocs</span> <span class="hljs-attr">database</span>=<span class="hljs-string">{database}/</span>&gt;</span></span>} /&gt;
</code></pre><p>Now, let's create a collection reference.</p>
<pre><code><span class="hljs-keyword">const</span> collectionRef = collection(database, <span class="hljs-string">'docsData'</span>)
</code></pre><p>Now for debouncing, we need the <strong>updateDocsData</strong> in a useEffect hook.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-function">() =&gt;</span> {

        }
 }, [])
</code></pre>
<p>Now, let's add a setTimeout function with an interval. This means that function will run after that specified interval. Make the interval <strong>1000 milliseconds</strong>, or <strong>1 second</strong>.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {

    }, <span class="hljs-number">1000</span>)  
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(updateDocsData)
  }, [])
</code></pre>
<p>Now, inside setTimeOut, let's add the updateDoc function. So inside the document variable, we are passing <strong>collectionRef</strong> and the <strong>ID</strong> from the params. And then, the updateDoc takes that variable document as first parameter.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
            updateDoc(<span class="hljs-built_in">document</span>, {

            })
        }, <span class="hljs-number">1000</span>)
</code></pre>
<p>Let's also import the <strong>doc</strong> function. It specifies which document to update using the ID as primary key.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
    updateDoc,
    collection,
    doc
} <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre>
<p>Now let's pass the data in the second parameter, in the updateDoc function.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
            updateDoc(<span class="hljs-built_in">document</span>, {
                <span class="hljs-attr">docsDesc</span>: docsDesc
            })
        }, <span class="hljs-number">1000</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(updateDocsData)
    }, [])
</code></pre>
<p>In the dependency array, add the state of <strong>docsDesc.</strong> So after we type something<strong>,</strong> the updateDoc function will run after 1 seconds.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
            updateDoc(<span class="hljs-built_in">document</span>, {
                <span class="hljs-attr">docsDesc</span>: docsDesc
            })
            .then(<span class="hljs-function">() =&gt;</span> {
                alert(<span class="hljs-string">'Saved'</span>)
            })
            .catch(<span class="hljs-function">() =&gt;</span> {
                alert(<span class="hljs-string">'Cannot Save'</span>)
            })
        }, <span class="hljs-number">1000</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(updateDocsData)
    }, [docsDesc])
</code></pre>
<p>So, type something in the editor, and it will be saved inside the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-135046.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And the data here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-135105.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If we add something further, we will append the previous data:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-135224.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-135242.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-get-the-data-back-from-the-database-to-the-editor">How to Get the Data Back from the Database to the Editor</h2>
<p>Now, if we go back and click any document, the data will be null, or erased. So, we have to get data from the database and set it to the editor.</p>
<p>We will use the <strong>onSnapshot</strong> function to do that.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
    updateDoc,
    collection,
    doc,
    onSnapshot
} <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {

    }

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span>(isMounted.current){
            <span class="hljs-keyword">return</span> 
        }

        isMounted.current = <span class="hljs-literal">true</span>;
        getData()
    }, [])
</code></pre>
<p>So, it's just like we did in the Docs component. We need to specify which data to get using the ID parameter. And then we pass this document to the onSnapshot function to get the data we need.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
        onSnapshot(<span class="hljs-built_in">document</span>, <span class="hljs-function">(<span class="hljs-params">docs</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(docs.data().docsDesc)
        })
    }
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-140423.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's set this <strong>docs.data().docsDesc</strong> in docsDesc state using setDocsDesc. So, if the document loads, it will be set there. </p>
<p>Add some data, then go back. And if you come back to the same component, the document description will be there.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-140723.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now in the home page where we are seeing all the data, we need to add the description too, if it exists.</p>
<pre><code> &lt;div dangerouslySetInnerHTML={{<span class="hljs-attr">__html</span>: doc.docsDesc}} /&gt;
</code></pre><p>We are using <strong>dangerouslySetInnerHTML</strong> because data is added in the form of tags in React Quill. That makes it easier to render the formatting. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-141304.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>See, I have added some formatting like <strong>Bold</strong> and <strong>Italic</strong> texts.</p>
<p>Now, we need to make some slight modifications. In the App.js file (where we are adding the document title) let's also add the description, which will initially be empty.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addData = <span class="hljs-function">() =&gt;</span> {
        addDoc(collectionRef, {
            <span class="hljs-attr">title</span>: title,
            <span class="hljs-attr">docsDesc</span>: <span class="hljs-string">''</span>
        })
        .then(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Data Added'</span>);
            handleClose()
        })
        .catch(<span class="hljs-function">() =&gt;</span> {
            alert(<span class="hljs-string">'Cannot add data'</span>)
        })
    }
</code></pre>
<p>So if we create a document, we will have the docsDesc in the Firestore Document. That will prevent our app from crashing when we go the EditDocs page.</p>
<p>Now, in the EditDocs page, let's add the document title so that it shows up on the top. Create a state called documentTitle and set it. </p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [documentTitle, setDocumentTitle] = useState(<span class="hljs-string">''</span>)

<span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
        onSnapshot(<span class="hljs-built_in">document</span>, <span class="hljs-function">(<span class="hljs-params">docs</span>) =&gt;</span> {
            setDocumentTitle(docs.data().title)
            setDocsDesc(docs.data().docsDesc);
        })
    }
</code></pre>
<p>And display this state on the top:</p>
<pre><code>&lt;h1&gt;{documentTitle}&lt;/h1&gt;
</code></pre><p>Here is the whole code for the <strong>EditDocs</strong> page till now:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useEffect, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> ReactQuill <span class="hljs-keyword">from</span> <span class="hljs-string">'react-quill'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'react-quill/dist/quill.snow.css'</span>;
<span class="hljs-keyword">import</span> {
    updateDoc,
    collection,
    doc,
    onSnapshot
} <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/firestore'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EditDocs</span>(<span class="hljs-params">{
    database
}</span>) </span>{
    <span class="hljs-keyword">const</span> isMounted = useRef()
    <span class="hljs-keyword">const</span> collectionRef = collection(database, <span class="hljs-string">'docsData'</span>)
    <span class="hljs-keyword">let</span> params = useParams();
    <span class="hljs-keyword">const</span> [documentTitle, setDocumentTitle] = useState(<span class="hljs-string">''</span>)
    <span class="hljs-keyword">const</span> [docsDesc, setDocsDesc] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> getQuillData = <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
        setDocsDesc(value)
    }
    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
            updateDoc(<span class="hljs-built_in">document</span>, {
                <span class="hljs-attr">docsDesc</span>: docsDesc
            })
                .then(<span class="hljs-function">() =&gt;</span> {
                    alert(<span class="hljs-string">'Saved'</span>)
                })
                .catch(<span class="hljs-function">() =&gt;</span> {
                    alert(<span class="hljs-string">'Cannot Save'</span>)
                })
        }, <span class="hljs-number">1000</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(updateDocsData)
    }, [docsDesc])

    <span class="hljs-keyword">const</span> getData = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
        onSnapshot(<span class="hljs-built_in">document</span>, <span class="hljs-function">(<span class="hljs-params">docs</span>) =&gt;</span> {
            setDocumentTitle(docs.data().title)
            setDocsDesc(docs.data().docsDesc);
        })
    }

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (isMounted.current) {
            <span class="hljs-keyword">return</span>
        }

        isMounted.current = <span class="hljs-literal">true</span>;
        getData()
    }, [])
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{documentTitle}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">ReactQuill</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{docsDesc}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{getQuillData}</span>
            /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
}
</code></pre>
<h2 id="heading-how-to-add-some-styling">How to Add Some Styling</h2>
<p>Now let's add some styling in this EditDocs page:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'editDocs-main'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{documentTitle}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'editDocs-inner'</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">ReactQuill</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">'react-quill'</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{docsDesc}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{getQuillData}</span>
                /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>And in the CSS, add the following styling:</p>
<pre><code class="lang-css">
<span class="hljs-selector-class">.editDocs-main</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Poppins'</span>, sans-serif;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">flex-direction</span>: column;
}

<span class="hljs-selector-class">.editDocs-inner</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0px</span> -<span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-number">2px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">0.75</span>);
    <span class="hljs-attribute">-webkit-box-shadow</span>: <span class="hljs-number">0px</span> -<span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-number">2px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">0.75</span>);
    <span class="hljs-attribute">-moz-box-shadow</span>: <span class="hljs-number">0px</span> -<span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-number">2px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">181</span>, <span class="hljs-number">0.75</span>);
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">750px</span>;
}

<span class="hljs-selector-class">.ql-container</span><span class="hljs-selector-class">.ql-snow</span> {
    <span class="hljs-attribute">border</span>: none <span class="hljs-meta">!important</span>;
}
</code></pre>
<p>We are adding a box shadow, we are removing the React Quill border, and we are centering everything. </p>
<p>This is how our edit document page looks now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-144341.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now for our final thing: let's replace our alerts with toast messages. We need one more package called <a target="_blank" href="https://www.npmjs.com/package/react-toastify">React Toastify</a>. So, let's install it.</p>
<pre><code>npm i react-toastify
</code></pre><p>Then we need to import these two things:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { ToastContainer, toast } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-toastify'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'react-toastify/dist/ReactToastify.css'</span>;
</code></pre>
<p>And then, the <strong></strong> component.</p>
<p>Now, for the toast message, simply do this:</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> updateDocsData = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = doc(collectionRef, params.id)
            updateDoc(<span class="hljs-built_in">document</span>, {
                <span class="hljs-attr">docsDesc</span>: docsDesc
            })
                .then(<span class="hljs-function">() =&gt;</span> {
                    toast.success(<span class="hljs-string">'Document Saved'</span>, {
                        <span class="hljs-attr">autoClose</span>: <span class="hljs-number">2000</span>
                    })
                })
                .catch(<span class="hljs-function">() =&gt;</span> {
                    toast.error(<span class="hljs-string">'Cannot Save Document'</span>, {
                        <span class="hljs-attr">autoClose</span>: <span class="hljs-number">2000</span>
                    })
                })
        }, <span class="hljs-number">1000</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(updateDocsData)
    }, [docsDesc])
</code></pre>
<p>We have <strong>toast.success</strong> for success alerts, and <strong>toast.error</strong> for error alerts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Screenshot-2022-05-08-145209.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>And there you have it, you've built a Google Docs clone. You are free to experiment and make this better.</p>
<p>You can get the full code here: <a target="_blank" href="https://github.com/nishant-666/Google-Docs-Clone">https://github.com/nishant-666/Google-Docs-Clone</a></p>
<p>Also, check out my channel <a target="_blank" href="https://www.youtube.com/c/CybernaticoByNishant">Cybernatico</a> for more amazing tutorials like these. </p>
<blockquote>
<p>Happy Learning.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Send Large Video Files – Share a Big File with Email ]]>
                </title>
                <description>
                    <![CDATA[ Sending large files through email can be quite challenging. This is because each email client has a size limit for file sharing. Gmail and Yahoo limit file size to 25MB, while outlook and iCloud limit files to 20MB. So, if you decide to send, for exa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-send-large-video-files-share-a-big-file-with-email/</link>
                <guid isPermaLink="false">66adf1476f5e63db3fc4361e</guid>
                
                    <category>
                        <![CDATA[ dropbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ email ]]>
                    </category>
                
                    <category>
                        <![CDATA[ File sharing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ videos ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 27 Apr 2022 19:51:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/technology-2125547_1280.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Sending large files through email can be quite challenging. This is because each email client has a size limit for file sharing.</p>
<p>Gmail and Yahoo limit file size to 25MB, while outlook and iCloud limit files to 20MB.</p>
<p>So, if you decide to send, for example, a video file larger than 25MB, you might get an error that the message was rejected by the server because it’s too large.</p>
<p>Some email clients won’t show an error, but instead, suggest how you should send the large video file. </p>
<p>For example, Gmail will suggest that you upload the video to Google Drive: 
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss1-7.png" alt="ss1-7" width="600" height="400" loading="lazy"></p>
<p>And Outlook will suggest that you upload the video to Microsoft OneDrive:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss2-8.png" alt="ss2-8" width="600" height="400" loading="lazy"></p>
<p>How then do you send a large video file through email? That’s what I’m going to show you in this article.</p>
<h2 id="heading-how-to-send-large-video-files-through-email-using-google-drive">How to Send Large Video Files through Email Using Google Drive</h2>
<p>Google Drive is a cloud-based storage service provided by Google for sharing files.</p>
<p>As already shown in this article, Gmail prompts you to upload a video file larger than 25MB to Google Drive and then convert the video to an accessible link.</p>
<p>If you are using another email client like Outlook, or Yahoo, you can still send the large video using Google Drive.</p>
<p>Upload the video to your Google Drive and click the “Get link” button:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss3-7.png" alt="ss3-7" width="600" height="400" loading="lazy"></p>
<p>Change the access from restricted to “Anyone with the link”:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss4-5.png" alt="ss4-5" width="600" height="400" loading="lazy"></p>
<p>Click “Copy link”, and then “Done”:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss5-5.png" alt="ss5-5" width="600" height="400" loading="lazy"></p>
<p>Click “Compose” and paste the link to your email editor. Provide every other necessary detail and click the “Send” button:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss6-5.png" alt="ss6-5" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-send-large-video-files-through-email-using-dropbox">How to Send Large Video Files through Email Using Dropbox</h2>
<p>Dropbox is another cloud-based storage service that lets you back up and sync files on multiple devices. You can upload up to 50GB file size to your Dropbox account if you have one.</p>
<p>To send large video files through email by using Dropbox, upload the video to your Dropbox account and copy the link:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss7-4.png" alt="ss7-4" width="600" height="400" loading="lazy"></p>
<p>Compose your email and paste the link in to send the large video file:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss8-4.png" alt="ss8-4" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-send-large-video-files-through-email-using-video-sharing-services">How to Send Large Video Files through Email Using Video Sharing Services</h2>
<p>You can send large video files through email by using video-sharing services like YouTube and Vimeo.</p>
<p>And yes, you can upload videos to YouTube without having a YouTube channel. As long as you have a Gmail account, you have access to Google services, including YouTube. So if you have a Google account, technically you can have a YouTube channel.</p>
<p>To upload videos to YouTube, click the Create button on the top-right corner and select “Upload video”:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss9-4.png" alt="ss9-4" width="600" height="400" loading="lazy"></p>
<p>Click on “SELECT FILES” to choose the file on your device:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss10-4.png" alt="ss10-4" width="600" height="400" loading="lazy"></p>
<p>Give the video a name and description, copy the link, and click “Next”:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss11-3.png" alt="ss11-3" width="600" height="400" loading="lazy"></p>
<p>Follow other prompts and choose whether you want to make the video public or private, then click “Save”:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss12-2.png" alt="ss12-2" width="600" height="400" loading="lazy"></p>
<p>Head over to your email client composer and paste in the link so you can send the large video file:
<img src="https://www.freecodecamp.org/news/content/images/2022/04/ss13-1.png" alt="ss13-1" width="600" height="400" loading="lazy"></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>You can’t send a large video file directly through email clients, but you can take advantage of the methods discussed in this article to send large video files.</p>
<p>Another way you can send a large video file through email is to compress the video through your native compressor or third-party file compressors. As long as the file is less than 20-25MB, you can send it through email.</p>
<p>But if you compress the video and it is still not less than 20-25MB, then you should use any of the methods pointed out in this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Google Docs Strikethrough – How to Cross Out Text in Google Docs ]]>
                </title>
                <description>
                    <![CDATA[ When you're writing, sometimes you might want to strike through certain text. This means adding a horizontal line that runs through a piece of text.  Here is what it looks like: you are an awesome person.  These are various use cases for strikethroug... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/google-docs-strikethrough-how-to-cross-out-text-in-google-docs/</link>
                <guid isPermaLink="false">66b0a2b77cd8dca6718a2240</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technical writing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ writing tips ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ihechikara Abba ]]>
                </dc:creator>
                <pubDate>Thu, 14 Apr 2022 17:49:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/siriwan-arunsiriwattana-gs0coXLmjdI-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're writing, sometimes you might want to strike through certain text. This means adding a horizontal line that runs through a piece of text. </p>
<p>Here is what it looks like: you are an awesome person.</p>
<p> These are various use cases for strikethroughs:</p>
<ul>
<li>To indicate that a piece or block of text that should be deleted.</li>
<li>To indicate that a piece or block of text is outdated.</li>
<li>To show task completion. This is usually seen in To-Do lists.</li>
<li>To convey an unrelated or humorous message when writing, and so on.</li>
</ul>
<p>In this article, we'll see how to strikethrough or cross out text when writing using Google Docs.</p>
<h2 id="heading-how-to-strikethrough-text-in-google-docs">How to Strikethrough Text in Google Docs</h2>
<p>There are two methods we can use when crossing out text in Google Docs – using a shortcut command or choosing the strikethrough option from the Format tab in the Google Docs header section. </p>
<h3 id="heading-how-to-strikethrough-text-in-google-docs-using-a-shortcut-command">How to Strikethrough Text in Google Docs Using a Shortcut Command</h3>
<p>Here are the steps to follow when using a shortcut command to strikethrough text in Google Docs:</p>
<ul>
<li>Open <a target="_blank" href="https://docs.google.com/">Google Docs</a> and create a blank document.</li>
<li>Write some text in your document. </li>
<li>Highlight the text you've written.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/gdocs.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ul>
<li>On windows, press <code>Alt</code> + <code>Shift</code> + <code>5</code>.</li>
<li>On Mac, press <code>⌘</code> + <code>Shift</code> + <code>X</code>.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/gdocs_strikethrough.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There you go, we have used a shortcut command to cross out text in Google Docs. </p>
<h3 id="heading-how-to-strikethrough-text-in-google-docs-using-the-format-tab">How to Strikethrough Text in Google Docs Using the Format Tab</h3>
<p>In this section, we'll see how we can strikethrough text in Google Docs using the Format option. Here are the steps:</p>
<ul>
<li>Open <a target="_blank" href="https://docs.google.com/">Google Docs</a> and create a blank document.</li>
<li>Write some text in your document. </li>
<li>Highlight the text you've written.</li>
<li>Click on the <code>Format</code> tab in the header.</li>
<li>Click on <code>Text</code>.</li>
<li>Click on the <code>Strikethrough</code> option.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/gdocs_tab.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After you have done this, your text should be crossed out.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we talked about strikethroughs in writing, their use cases and how to strikethrough/cross out text in Google Docs.</p>
<p>Thank you for reading! But really, thank's for reading! :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to do a Hanging Indent in Google Docs ]]>
                </title>
                <description>
                    <![CDATA[ A hanging indent is an easy way to make your documents look more professional. Google Docs has built in functionality to create this. What is a Hanging Indent? A hanging indent is a type of indentation where the first line of a paragraph is not inden... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-do-a-hanging-indent-in-google-docs/</link>
                <guid isPermaLink="false">66b8d3e60c9c1d363b7c4226</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Quincy Larson ]]>
                </dc:creator>
                <pubDate>Wed, 06 Apr 2022 21:02:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/luca-bravo-K-HMCiChjag-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A hanging indent is an easy way to make your documents look more professional. Google Docs has built in functionality to create this.</p>
<h3 id="heading-what-is-a-hanging-indent">What is a Hanging Indent?</h3>
<p>A hanging indent is a type of indentation where the first line of a paragraph is not indented, but subsequent lines in the same paragraph are indented.</p>
<p>Here is an example of what a Hanging Indent looks like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Untitled_document_-_Google_Docs_---2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In Google Docs, you can create a hanging indent by following these simple steps:</p>
<p><strong>Step 1</strong>: Select the text you want to format. You can do this by triple-clicking the paragraph.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Untitled_document_-_Google_Docs_--.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Step 2</strong>: Click the "Format" menu. Then choose "Align and Indent". Then choose "Indentation options."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Untitled_document_-_Google_Docs_---1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Step 3</strong>: From this menu, you can choose "Hanging." If you want, you can specify by how much you want to indent. For this tutorial, I've left that value at the default value of 0.5.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/Untitled_document_-_Google_Docs_---3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And presto! You have a sophisticated-looking paragraph that uses hanging indentation.</p>
<p>I hope you've found this helpful. If you want to learn more about programming and technology, try <a target="_blank" href="https://www.freecodecamp.org/learn">freeCodeCamp's core coding curriculum</a>. It's free.</p>
<p>Thanks and have a fantastic day.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Insert a Text Box in Google Docs – Add Textbox Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ Google Docs is one of the most popular text processors. It has many features available to help you visually enhance your writing and make specific parts stand out more. One of the ways you can add more functionality to your documents is by adding a t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-insert-a-text-box-in-google-docs-add-textbox-tutorial/</link>
                <guid isPermaLink="false">66b1e4200968943127cc5f05</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ how-to ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technical writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Dionysia Lemonaki ]]>
                </dc:creator>
                <pubDate>Fri, 24 Sep 2021 17:42:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/kelly-sikkema-Plso5cHu9w0-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Google Docs is one of the most popular text processors.</p>
<p>It has many features available to help you visually enhance your writing and make specific parts stand out more.</p>
<p>One of the ways you can add more functionality to your documents is by adding a textbox.</p>
<p>A textbox helps make any topics you want to highlight and bring attention to more prominent.</p>
<p>Your readers and target audience will better understand the information you're trying to convey and the message you want to get across.</p>
<p>It's also a helpful method for note-taking. Text boxes help point out topics you want to pay extra attention to and not miss.</p>
<p>In this quick and easy guide, you'll learn how to insert a textbox into your Google Document with just a couple of simple steps.</p>
<p>Let's get started!</p>
<h2 id="heading-how-to-add-a-textbox-in-google-docs">How to add a Textbox in Google Docs</h2>
<p>First of all, make sure you're logged into your <a target="_blank" href="https://myaccount.google.com/?utm_source=sign_in_no_continue&amp;nlr=1">Google Account</a>.</p>
<p>Then, navigate to <a target="_blank" href="https://docs.google.com/document/u/0/?tgif=d">Google Docs</a> and create a new document by double-clicking on 'Blank'. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-23-at-10.56.09-AM.jpeg" alt="Screenshot-2021-09-23-at-10.56.09-AM" width="600" height="400" loading="lazy"></p>
<p>If you want to add a textbox to an existing document, choose the document you want from the options in 'Recent Documents' by double-clicking on it.</p>
<p>Once you've opened (or created) a Google Doc, click on 'Insert'. A drop-down menu will appear, and from there you navigate to 'Drawing'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-7.10.24-PM.jpeg" alt="Screenshot-2021-09-22-at-7.10.24-PM" width="600" height="400" loading="lazy"></p>
<p>From there, click on 'Drawing' and select 'New'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-7.14.24-PM.jpeg" alt="Screenshot-2021-09-22-at-7.14.24-PM" width="600" height="400" loading="lazy"></p>
<p>Once you click 'New', a new window will open up. This is the Drawing Tool and the place where you'll be able to insert a textbox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-7.17.20-PM.png" alt="Screenshot-2021-09-22-at-7.17.20-PM" width="600" height="400" loading="lazy"></p>
<p>In the toolbar, select the 'Text box' icon. It's the square with the letter 'T' inside it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-7.22.27-PM.jpeg" alt="Screenshot-2021-09-22-at-7.22.27-PM" width="600" height="400" loading="lazy"></p>
<p>Once you've tapped that icon, you'll notice that your cursor has changed. It now looks like a little plus sign or a 'crosshair cursor' as it's known. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-7.57.02-PM.jpeg" alt="Screenshot-2021-09-22-at-7.57.02-PM" width="600" height="400" loading="lazy"></p>
<p>This now indicates that you can start drawing your textbox and give it a shape.</p>
<p>Drag and move the crosshair cursor to make a textbox. Then adjust the size you want it to have by clicking and dragging its corners.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-23-at-11.46.22-AM.png" alt="Screenshot-2021-09-23-at-11.46.22-AM" width="600" height="400" loading="lazy"></p>
<p>To add some text, double click inside the textbox that you just created. You'll see a blinking cursor come up, indicating that you can start writing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-8.04.00-PM.png" alt="Screenshot-2021-09-22-at-8.04.00-PM" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-customize-a-textbox-in-google-docs">How to Customize a Textbox in Google Docs</h2>
<p>To make further edits to the text you've added, such as aligning it in the center, changing the color, font-style, or font-family, adding lists, and so on, click on the three dots on the right hand side.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-4.55.18-PM.jpeg" alt="Screenshot-2021-09-24-at-4.55.18-PM" width="600" height="400" loading="lazy"></p>
<p>You can add a background-color if you want to make the textbox stand out more.</p>
<p>You do this by selecting the 'fill color' icon which is the paint bucket  icon. A color picker will appear for you to select your desired background-color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-22-at-8.06.11-PM.jpeg" alt="Screenshot-2021-09-22-at-8.06.11-PM" width="600" height="400" loading="lazy"></p>
<p>If you want, you can also add a color to the box's border. Select the 'Border color' icon and pick a color of your choice.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.00.55-PM.jpeg" alt="Screenshot-2021-09-24-at-5.00.55-PM" width="600" height="400" loading="lazy"></p>
<p>You can also change the thickness of the border. Select the 'Border weight' icon which is on the right of the 'Border color'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.03.32-PM.jpeg" alt="Screenshot-2021-09-24-at-5.03.32-PM" width="600" height="400" loading="lazy"></p>
<p>You can even change the border style with the 'Border dash' icon, giving the border a dotted style.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.04.45-PM.jpeg" alt="Screenshot-2021-09-24-at-5.04.45-PM" width="600" height="400" loading="lazy"></p>
<p>To save your work, click 'Save and Close'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.09.12-PM.jpeg" alt="Screenshot-2021-09-24-at-5.09.12-PM" width="600" height="400" loading="lazy"></p>
<p>And there you have it, the textbox now appears in your Google Document.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.05.00-PM.png" alt="Screenshot-2021-09-24-at-5.05.00-PM" width="600" height="400" loading="lazy"></p>
<p>If you want to make further changes to the textbox, click on it and the contextual menu will appear.</p>
<p>From here, you'll be able to click 'Edit' and be taken back to the Drawing Tool, or you can adjust the text and margin in line, wrap or break the text inside the textbox, and more.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.27.35-PM.png" alt="Screenshot-2021-09-24-at-5.27.35-PM" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-insert-custom-shapes-in-google-docs">How to Insert Custom Shapes in Google Docs</h2>
<p>Besides just adding a textbox, there are a variety of different available shapes to choose from and add to your documents.</p>
<p>You can combine these shapes (such as arrows, mathematical equation signs, and so on) with textboxes to make your document more interactive and stand out even more.</p>
<p>To create a custom shape, in the Drawing Tool (Insert -&gt; Drawing -&gt; New), navigate to the 'Shape' icon which is on the left of the 'Text box' icon.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.21.30-AM.jpeg" alt="Screenshot-2021-09-24-at-10.21.30-AM" width="600" height="400" loading="lazy"></p>
<p>After clicking on it, you'll see a dropdown menu with all the available categories – 'Shapes', 'Arrows', 'Callouts', 'Equation'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-11.35.13-AM.png" alt="Screenshot-2021-09-24-at-11.35.13-AM" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.26.42-AM.jpeg" alt="Screenshot-2021-09-24-at-10.26.42-AM" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.26.53-AM.jpeg" alt="Screenshot-2021-09-24-at-10.26.53-AM" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.27.04-AM.jpeg" alt="Screenshot-2021-09-24-at-10.27.04-AM" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.27.12-AM.jpeg" alt="Screenshot-2021-09-24-at-10.27.12-AM" width="600" height="400" loading="lazy"></p>
<p>To create a shape, choose one you like and then click on the drawing area so that it appears. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-10.57.41-AM.png" alt="Screenshot-2021-09-24-at-10.57.41-AM" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.39.39-PM.png" alt="Screenshot-2021-09-24-at-5.39.39-PM" width="600" height="400" loading="lazy"></p>
<p>From there you can adjust the size of the shape and move it around by draggind and dropping its edges (via the little squares at the edges of the spape).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-5.41.46-PM.png" alt="Screenshot-2021-09-24-at-5.41.46-PM" width="600" height="400" loading="lazy"></p>
<p>Similarly to the textbox, you can add a background-color and a border color  to it and adjust any text you add in the shape. You do this by clicking on the three dots on the far right corner of the toolbox where there are more options for further customization.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-11.11.54-AM.png" alt="Screenshot-2021-09-24-at-11.11.54-AM" width="600" height="400" loading="lazy"></p>
<p>When you've finished your work, click 'Save and Close'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-24-at-11.43.03-AM.jpeg" alt="Screenshot-2021-09-24-at-11.43.03-AM" width="600" height="400" loading="lazy"></p>
<p>Your shape will then be added to your Google Document.</p>
<p>Thanks for reading! Have fun customizing your Google Docs.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Save a Google Doc as a PDF ]]>
                </title>
                <description>
                    <![CDATA[ Google Docs is an essential productivity tool for digital work. This article will cover how to save a Google Doc as a PDF on the Desktop version of Google Docs. What Is Google Docs Used For? You can use Google Docs for many different tasks. For examp... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-save-a-google-doc-as-a-pdf/</link>
                <guid isPermaLink="false">66b1e42f6500ee13f33bd576</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ how-to ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Dionysia Lemonaki ]]>
                </dc:creator>
                <pubDate>Tue, 14 Sep 2021 17:58:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/google-doc-to-pdf.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Google Docs is an essential productivity tool for digital work.</p>
<p>This article will cover how to save a Google Doc as a PDF on the Desktop version of Google Docs.</p>
<h2 id="heading-what-is-google-docs-used-for">What Is Google Docs Used For?</h2>
<p>You can use Google Docs for many different tasks.</p>
<p>For example, you can jot down key concepts in a Doc while you're watching a coding tutorial or reading through an article.</p>
<p>Or you can use it to create an e-book or other learning material for your students.</p>
<p>Google Docs is also a staple in the workplace for sharing documents with your teammates.</p>
<p>You can also use it to craft your perfect résumé or cover letter.</p>
<p>And the list goes on.</p>
<p>When you're ready to save your Google Doc, you have the choice of saving it in various formats. Let's look at some of them now.</p>
<h2 id="heading-why-save-a-google-doc-as-a-pdf">Why Save a Google Doc as a PDF?</h2>
<p>A PDF, one of the most popular document types, is short for Portable Document Format and was created by Adobe in 1991.</p>
<p>Before then, files shared digitally were somewhat problematic as the formatting of documents could get seriously altered depending on what system you were using and so on.</p>
<p>Adobe created PDFs so that people could send electronic files in a straightforward way, without their formatting getting compromised.</p>
<p>Thanks to PDFs, your files look as you intended. The styles the receiver sees are the original ones you saved when creating the document.</p>
<p>Without a doubt, the styles in the document are going to be preserved.</p>
<h2 id="heading-how-to-save-a-google-doc-as-a-pdf-file">How to Save a Google Doc as a PDF File</h2>
<p>The method we'll discuss now is for downloading any Google Doc file in PDF format on your local computer system.</p>
<p>First, log into your <a target="_blank" href="https://myaccount.google.com/">Google Account</a>.</p>
<p>Next, open your <a target="_blank" href="https://drive.google.com/drive/my-drive">Google Drive Account</a>. </p>
<p>You can view all your saved documents on the Google Drive home screen.</p>
<p>Go ahead and open the document of your choice by double-clicking on the document. You can also open it by holding down the <code>control</code> key and touchpad at the same time for MacOs or right-clicking for WindowsOS. Then select <code>Open With</code> &gt; <code>Google Docs</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-14-at-5.05.09-PM.png" alt="Screenshot-2021-09-14-at-5.05.09-PM" width="600" height="400" loading="lazy"></p>
<p>If you don't have a document you want to save as a PDF already, you can create a new file altogether by selecting the New button and then Google Docs. Then either create a blank document or choose a template instead.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-14-at-5.08.27-PM.png" alt="Screenshot-2021-09-14-at-5.08.27-PM" width="600" height="400" loading="lazy"></p>
<p>Once the file is opened, edited, and ready to save, choose <code>File</code> &gt; <code>Download</code> &gt; <code>PDF Document(.pdf)</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screenshot-2021-09-14-at-5.14.40-PM.jpeg" alt="Screenshot-2021-09-14-at-5.14.40-PM" width="600" height="400" loading="lazy"></p>
<p>The PDF document will be downloaded on your computer and saved in your Downloads folder by default.</p>
<p>You will now have access to the Google Doc you created in Google Drive in a PDF format locally on your computer system.</p>
<h2 id="heading-how-to-save-a-pdf-back-to-google-drive">How to Save a PDF Back to Google Drive</h2>
<p>What if you want to save this PDF in Google Drive?</p>
<p>All you need to do is go to your Downloads folder (or wherever you saved your file), select the file, and drag it into Google Drive.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screen-Recording-2021-09-14-at-06.09.35-PM.gif" alt="Screen-Recording-2021-09-14-at-06.09.35-PM" width="600" height="400" loading="lazy"></p>
<p>Now you have both the Google Doc and PDF version saved in your Google Drive.</p>
<p>And there you have it.</p>
<p>In this quick guide, you learned how to save Google Doc documents as PDFs on both your computer system and Google Drive.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Google Docs Voice Typing – How to Use Speech-to-Text in a Google Doc ]]>
                </title>
                <description>
                    <![CDATA[ Speech-to-Text is a really useful accessibility tool if typing is difficult for you. Or you can also use it if you like to think out loud and transcribe what you say. In this tutorial, I'll show you how to use speech-to-text in Google Docs. Do note, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/google-docs-voice-typing-how-to-use-speech-to-text-in-a-google-doc/</link>
                <guid isPermaLink="false">66b0c3894d2b90ec4a447a54</guid>
                
                    <category>
                        <![CDATA[ editing tips ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ilenia Magoni ]]>
                </dc:creator>
                <pubDate>Fri, 30 Jul 2021 20:09:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/pexels-george-milton-6953871.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Speech-to-Text is a really useful accessibility tool if typing is difficult for you. Or you can also use it if you like to think out loud and transcribe what you say.</p>
<p>In this tutorial, I'll show you how to use speech-to-text in Google Docs. Do note, though, that this feature is available only if you're using Google's Chrome browser.</p>
<h2 id="heading-how-to-activate-the-speech-to-text-tool">How to Activate the Speech-to-Text Tool</h2>
<p>You can activate speech-to-text from the Tools menu – it is the fourth menu item from the bottom. Or you can use the <code>Ctrl+Shift+S</code> (on Windows) or <code>Command+Shift+S</code> (on Mac) shortcut to activate it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/image-101.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Tool menu. The Voice typing menu item is the tenth item from the top, or the fourth from the bottom.</em></p>
<p>This will open a little tab with a microphone and a dropdown menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/image-102.png" alt="Image" width="600" height="400" loading="lazy">
<em>The voice typing tab.</em></p>
<p>You can drag it around with the three horizontal dots at the top. Next to those dots you can click the X to close it. Just below you'll see the dropdown menu where you can change languages (and it shows what language is currently set). Then below that there's the big square button with a grey microphone in the middle.</p>
<p>If you want to change the language setting for the Voice Typing tool, you need to use the drop down menu. It will let you choose between many languages. Just select the language you prefer, and you are ready to start using it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/image-105.png" alt="Image" width="600" height="400" loading="lazy">
<em>The drop down menu expanded. It has a lot of languages you can choose from.</em></p>
<h2 id="heading-how-to-use-voice-typing-in-google-docs">How to Use Voice Typing in Google Docs</h2>
<p>You can start voice typing by clicking on the microphone button. When it's activated, it will become red. </p>
<p>If you get an alert from Google Docs asking for permission to use your microphone, go ahead and grant permission or you will not be able to use voice typing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/image-104.png" alt="Image" width="600" height="400" loading="lazy">
<em>The microphone icon when activated: all the other options disappear, and the microphone icon turns red and is now surrounded by a red circle.</em></p>
<p>Now, start speaking, and Google Docs will transcribe what you say. You need to speak clearly and not too quickly for better results. </p>
<p>While Google is interpreting what you have said there will be a pattern of little squares shown where the words will appear after it has finished elaborating.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/image-106.png" alt="Image" width="600" height="400" loading="lazy">
<em>While Google is elaborating, a pattern of squares similar to this will be shown. When elaboration is finished, it will be replaced with the words.</em></p>
<h2 id="heading-voice-commands">Voice Commands</h2>
<p>Writing a document often includes editing and formatting. Voice commands allow you to do all the editing and formatting using only your voice.</p>
<p>Voice commands are available only for the English language. When you say certain words and phrases, like "move to the end of the line" or "select paragraph", those actions will be executed. </p>
<p>You can find the whole list of available commands by saying "voice commands list", or in the <a target="_blank" href="https://support.google.com/docs/answer/4492226">Google Docs guide article with the complete list of available voice commands</a>.</p>
<h2 id="heading-voice-typing-and-voice-commands-in-action">Voice Typing and Voice Commands in action</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/uFXMwa-PXvY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Voice typing, or speech-to-text, is a useful accessibility tool. I hope this article has taught you how to use it, and you will be able to write with less typing!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Word Count in Google Docs Tutorial – Counting Words and Characters in a Google Doc or Word File ]]>
                </title>
                <description>
                    <![CDATA[ If you need to know the number of words or characters in a Google Doc, it's easy to find out using the tools Google Docs itself offers you. Whether it's for a Google Doc or an imported Word file, it works the same way – and I'll show you how ]]>
                </description>
                <link>https://www.freecodecamp.org/news/word-count-in-google-docs-tutorial-counting-words-and-characters-in-a-google-doc-or-word-file/</link>
                <guid isPermaLink="false">66b0c3c3c82f8da076e5b02a</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ilenia Magoni ]]>
                </dc:creator>
                <pubDate>Mon, 19 Apr 2021 20:40:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you need to know the number of words or characters in a Google Doc, it's easy to find out using the tools Google Docs itself offers you.</p>
<p>Whether it's for a Google Doc or an imported Word file, it works the same way – and I'll show you how in this quick guide.</p>
<h2 id="heading-where-to-find-the-word-count-tool-in-google-docs">Where to find the word count tool in Google Docs</h2>
<p>You can find the word count tool in the Tools menu – it's the second item in the menu at the top. Or you can use the <code>Ctrl+Shift+C</code> keyboard shortcut.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-53.png" alt="Image" width="600" height="400" loading="lazy">
<em>Tools menu and word count feature.</em></p>
<h2 id="heading-how-word-count-works-in-google-docs">How word count works in Google Docs</h2>
<p>The word count tool shows the statistics of your current document. So if you click on "Word count" in the Tools menu, or use that keyboard shortcut, it will display the stats for the document you're working on.</p>
<p>It first shows first the number of pages in your document, then the number of words, then the number of characters, and last the number of characters excluding spaces. You can see an example below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-54.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Just click "Ok" or "Cancel" to close that window.</p>
<h2 id="heading-how-to-have-the-documents-statistics-always-visible-on-the-page">How to have the document's statistics always visible on the page</h2>
<p>If you're aiming for a certain number of words in a document, you might want to monitor your word count constantly – without having to reopen the tool all the time.</p>
<p>You can set it up so the stats are always visible on your current page. In the word count tool, below everything else, there is a checkbox called "Display word count while typing". If you check that box, it will make the word count appear in the bottom right corner of the document window, like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-55.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The number of words is actually a drop down menu. You can click on it to see all statistics and change which statistic is visible when the dropdown menu is closed. It also gives you an option to hide the word count tool again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-56.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Google Docs easily shows you the number of words, pages, and characters in your document using the Word count tool. And it's easy to open it from the Tools menu, or using the <code>Ctrl+Shift+C</code> keyboard shortcut.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Google Docs Landscape Tutorial – How to Make a Google Doc Landscape Orientation ]]>
                </title>
                <description>
                    <![CDATA[ Most documents look better in portrait orientation. But there are times when you need the extra horizontal space to display graphs or for something like a certificate. In this article we'll go over how to change the orientation of a document on Googl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/google-docs-landscape-tutorial-how-to-make-a-google-doc-landscape-orientation/</link>
                <guid isPermaLink="false">66ac87f859c54e72c7730914</guid>
                
                    <category>
                        <![CDATA[ Google ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kristofer Koishigawa ]]>
                </dc:creator>
                <pubDate>Fri, 25 Sep 2020 09:24:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c988b740569d1a4ca1aa4.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most documents look better in portrait orientation. But there are times when you need the extra horizontal space to display graphs or for something like a certificate.</p>
<p>In this article we'll go over how to change the orientation of a document on Google Docs to landscape, how to make that the default orientation, and more.</p>
<h2 id="heading-how-to-change-a-google-doc-to-landscape-on-desktop">How to change a Google Doc to landscape on desktop</h2>
<p>Before we start, an important note: It's not possible to change only part of a Google Doc to landscape orientation. At the time of writing, the whole Google Doc has to be in either landscape or portrait orientation.</p>
<p>With that out of the way, here's how to change the orientation of a Google Doc to landscape.</p>
<h3 id="heading-step-1-open-the-page-setup-menu">Step 1: Open the "Page setup" menu</h3>
<p>First, click "File" in the upper-left corner, then click "Page Setup":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/step-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-2-set-the-page-orientation-to-landscape">Step 2: Set the page orientation to landscape</h3>
<p>In the "Page setup" menu, you'll see two options for the page orientation: "Portrait" and "Landscape".</p>
<p>Select "Landscape", then click the blue "OK" button on the bottom-right:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/step-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once you do that, your entire document will be in landscape:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/image-18.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Because the entire document has changed orientation, there's a good chance that any existing tables, graphs, images, and other elements in your document will need to be adjusted.</p>
<p>So that's simple enough, but what if you're using Google Docs on a mobile device? Fortunately that's also pretty straightforward.</p>
<h2 id="heading-how-to-change-a-google-doc-to-landscape-on-mobile">How to change a Google Doc to landscape on mobile</h2>
<p>Like with Google Docs on desktop, it's not possible to change just part of a document to landscape orientation – it's all or nothing.</p>
<p>Also, I'll be using Google Docs on Android for this portion of the tutorial, though the process should be similar on iOS.</p>
<p>And with that, let's jump in.</p>
<h3 id="heading-step-1-open-the-page-setup-menu-1">Step 1: Open the "Page setup" menu</h3>
<p>Open the document, then tap the pencil icon in the bottom-right:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-1.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Tap the three vertical dots in the upper-right corner:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-2.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p> Then tap "Page setup":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-3.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-2-set-the-page-orientation-to-landscape-1">Step 2: Set the page orientation to landscape</h3>
<p>In the "Page setup" menu, tap "Orientation":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-4.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Select "Landscape", then tap the arrow in the upper-left to go back to the "Page setup" menu:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-5.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Press the arrow in the upper-left to go back to the editor screen.</p>
<p>Even though your document is now in landscape orientation, it will look just like it did before:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-6.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>I assure you, this is in landscape mode!</em></p>
<p>To see the new orientation, you'll need to view your Google Doc in "Print layout" mode.</p>
<h3 id="heading-step-3-toggle-the-print-layout-mode-optional">Step 3: Toggle the print layout mode (optional)</h3>
<p>To confirm your document is in landscape orientation, tap the three vertical dots in the upper-right and tap the "Print layout" toggle:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-7.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now you can view your document in all its landscape glory:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/mobile-8.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Note: You may need to zoom out to see your entire document</em></p>
<p>That's it! Now you should have everything you need to change the page orientation of a Google Doc on both desktop and mobile devices.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Affordable Air Quality Sensor for Your Home ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff This post is originally from www.jaredwolff.com I got my hands on some of the mesh based Particle boards not too long ago. I’ve been itching to try them out but haven’t quite figured out the project. One thing has been bothering me tho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-affordable-and-proven-air-quality-sensor/</link>
                <guid isPermaLink="false">66d8504be86088251dd27bb9</guid>
                
                    <category>
                        <![CDATA[ Electronics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jun 2019 20:10:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/Copy-of-Particle-Sensor-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p><strong>This post is originally from <a target="_blank" href="https://www.jaredwolff.com/homemade-indoor-air-quality-sensor">www.jaredwolff.com</a></strong></p>
<p>I got my hands on some of the mesh based Particle boards not too long ago. I’ve been itching to try them out but haven’t quite figured out the project.</p>
<p>One thing has been bothering me though: air quality. I spend a good amount of time in my office tinkering, soldering, coding and writing. I sneeze occasionally so I always wondered, how bad is it? The house is also prone to mold exposure during the hot months which had me concerned.</p>
<p>So why not cook something up?</p>
<h2 id="heading-whats-needed">What’s needed</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/ingredients.jpg" alt="All the parts needed" width="600" height="400" loading="lazy"></p>
<p>The most important sensor is the <a target="_blank" href="https://www.honeywellscportal.com/honeywell-sensing-hpm-series-particle-sensors-datasheet-32322550-e-en.pdf">Honeywell HPM series</a> PM2.5/PM10 sensor. This tells you how many micrograms of material is floating around in a cubic volume of space. i.e. it counts the little particles flying around in your air.</p>
<p>Second to that, is the <a target="_blank" href="https://ams.com/documents/20143/36005/CCS811_DS000459_7-00.pdf">AMS CCS811</a>. This sensor tells you the total amount of volatile organic compounds are in the air along with things like C02. It’s another datapoint which is interesting to see. I’ve previously placed this sensor in our basement only to be surprised and see huge spikes in VOC and C02 levels from our (oil burning) furnace turning on in the morning. Time for better ventilation!</p>
<p>Finally,  the <a target="_blank" href="https://www.silabs.com/documents/public/data-sheets/Si7021-A20.pdf">Silicon Labs Si7021</a> temperature and humidity sensor. These two bits of environmental data are useful. More importantly they’re used by the algorithm in the CCS811 to compute the TVOC and C02.  Considering the cost of the CCS811, I’m surprised it doesn’t have these measurements on board but maybe in their next revision..</p>
<h2 id="heading-wiring-it-all-together">Wiring it all together</h2>
<p>It’s time to wire everything together. At the very least you’ll need:</p>
<ol>
<li>Solder-less breadboard hookup wire</li>
<li>A solder-less breadboard</li>
<li>A <a target="_blank" href="https://www.adafruit.com/product/3566">CCS811 breakout board</a> from Adafruit (<a target="_blank" href="https://learn.adafruit.com/adafruit-ccs811-air-quality-sensor?view=all">more details here</a>)</li>
<li>A <a target="_blank" href="https://www.adafruit.com/product/3251">Si7021 breakout  from Adafruit</a>(<a target="_blank" href="https://learn.adafruit.com/adafruit-si7021-temperature-plus-humidity-sensor?view=all">more details here</a>)</li>
<li><a target="_blank" href="https://www.particle.io/mesh/">A Particle board of your choice.</a></li>
<li>A <a target="_blank" href="https://www.jaredwolff.com/store/dust-sensor/">HPMA115 Particle sensor</a></li>
<li>Pre assembled Molex cable for the HPMA115 (Molex P/N 0151340803 or similar)</li>
<li>Some 0.1” pitch headers</li>
</ol>
<p>I’ve included a Fritzing example with this project. There’s also a hookup image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/particle-squared-hookup-diagram.jpg" alt="Fritzing Hookup Diagram" width="600" height="400" loading="lazy">
<strong>Note:</strong> the original Fritzing diagram was incorrect. Both Vin of the CCS811 and Si7021 should be connected to the 3.3V on the Particle</p>
<p>An Adafruit Feather is used to represent the Particle Argon. Particle does not have Fritzing models quite yet.</p>
<p>As you can see everything is hooked up except for the PM2.5 sensor. The pinout is included below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-23_at_12.31.03_PM.png" alt="Particle sensor pinout" width="600" height="400" loading="lazy"></p>
<p>The most important pins are the 5V, GND, RX and TX pins. The other ones can stay disconnected if you choose. Here are the connections called out:</p>
<p>    5V     -&gt; USB
    GND    -&gt; GND
    RX     -&gt; TX (on the Argon)
    TX     -&gt; RX (on the Argon).</p>
<p>Here’s a picture of everything assembled on a solder-less breadboard.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/DSC01397.jpg" alt="Everything assembled on breadboard" width="600" height="400" loading="lazy"></p>
<p>Another important note is that I modified the cable for the HPMA so they had male pins on the end. That made it easy to insert into the solder-less breadboard. Here’s a zoomed in shot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/DSC01370.jpg" alt="Soldered pin" width="600" height="400" loading="lazy"></p>
<p>When you purchase the cable for the PM2.5 sensor it came pre-populated with 8 wires. To make things simpler, you can remove 4 of the wires that are not used. The best way to do that is take a sharp tipped tool (dental pick, sewing needle, etc) and stick it under the clips I’ve pointed out in red below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/DSC01371.jpg" alt="Clips holding the wires in" width="600" height="400" loading="lazy"></p>
<p>Then, once you have your sharp implement underneath, tug on the wire and it should slide out.</p>
<p>Now you have less wire and less headache. You can use this technique to modify any Molex-like connector.</p>
<h2 id="heading-plumbing-the-firmware">Plumbing the firmware</h2>
<p>For this project I decided to keep my code consistent with the Wiring/Arduino-like API. That means object oriented C++. It’s been a while where I’ve coded in C++ so when you’re looking at the codebase and wondering “why the hell did he do that!?” Sorry, not sorry. ?</p>
<p>The best way to get started is to use Visual Code with the Particle plugins for this project. <a target="_blank" href="https://www.particle.io/workbench/">Click here to get started if you're not already setup.</a></p>
<h3 id="heading-si7021">Si7021</h3>
<p>The Si7021 is super simple. It only has 4 active pins out of the 6 on the chip.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-23_at_1.18.21_PM.png" alt="Si7021 pinout" width="600" height="400" loading="lazy">
(Copied directly from the Si7021 documentation)</p>
<p>The best say to read the temperature/humidity sensor is to issue a blocking read command. In an embedded world, this is not ideal. Unfortunately, there’s no way to know when the readings are ready because there is no interrupt pin.</p>
<p>As described in the data-sheet, you first write the command and then attempt to read directly from the device. The code looks something like this:</p>
<pre><code>    <span class="hljs-comment">// Si7021 Temperature</span>
    Wire.beginTransmission(SI7021_ADDRESS);
    Wire.write(SI7021_TEMP_HOLD_CMD); <span class="hljs-comment">// sends one byte</span>
    Wire.endTransmission();           <span class="hljs-comment">// stop transaction</span>
    Wire.requestFrom(SI7021_ADDRESS, <span class="hljs-number">2</span>);

    <span class="hljs-comment">// Get the raw temperature from the device</span>
    uint16_t temp_code = (Wire.read() &amp; <span class="hljs-number">0x00ff</span>) &lt;&lt; <span class="hljs-number">8</span> | (Wire.read() &amp; <span class="hljs-number">0x00ff</span>);
</code></pre><p>Wire the address of the device, write the command and then subsequently read the number of bytes necessary (Two in this case) The Si7021 will then stretch the clock until the reading has completed.</p>
<p>I didn’t mess around with other settings. Depending on your environment you may have to tweak how much current to feed the heater. You’re mileage may vary so prepare accordingly!</p>
<p>Finally, these readings are read on a reoccurring timer. I originally was using the <code>millis()</code> call and calculating the different of the start and current time but this eventually breaks (in 50 or so days). Instead I decided to use a system timer (similar to if not the same as the APP_TIMER in the NRF SDK)</p>
<pre><code>Timer timer(MEASUREMENT_DELAY_MS, timer_handler);
</code></pre><p>That way you get your interrupt always at <code>MEASUREMENT_DELAY_MS</code> no matter what! (In my case <code>MEASUREMENT_DELAY_MS</code> = 60000 ms == 60s)</p>
<h3 id="heading-the-ccs811">The CCS811</h3>
<p>The CCS811 gives you a bit more freedom to play but it comes with it’s own <em>specialness</em>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-23_at_2.34.14_PM.png" alt="CCS811 pinout" width="600" height="400" loading="lazy"></p>
<p>In most cases the ADDR pin is set low. This pin modifies one bit of the address. This is useful if you have two of the same device or two devices with the same address on the same I2C bus.</p>
<p>The CCS811 also has a few handy input and output pins. The most important is the interrupt pin. Whenever a reading is complete, this open drain pin will be pulled low. It will only get reset once you read the status  register. This is great for asynchronous reads that way you’re not locking up your MCU.</p>
<p>One important point is that the CCS811 does require you to issue a “start” command. This forces the internal MCU to start executing the TVOC/CO2 sensing algorithm. If you attempt to read the data registers before the application is started you will get bogus data. (The command is 0x90)</p>
<p>In the firmware, the CSS811 is processed in the same loop as the Si7021. The code pulls the available data from the CSS811 asynchronous readings. No blocking code!</p>
<h3 id="heading-the-hpma115">The HPMA115</h3>
<p>The particle sensor is a bit more tricky. When it is turned on, the device starts sending particulate data on a regular interval. i.e. it’s in auto-send mode every time it powers up.</p>
<p>I tried previously to configure the device but sometimes I wouldn’t get a response back. It was always hit and miss. It drove me crazy.</p>
<p>So, in order to turn the device off wen you’re not using it I highly suggest using a load switch of some kind. Not only will this save power but according to Honeywell, it will also increase the lifespan of the fan.</p>
<p>The flow of the readings:</p>
<ul>
<li>Every minute turn it on</li>
<li>Wait for data to be sent</li>
<li>Read the reading asynchronously via UART</li>
<li>Turn it off</li>
<li>Bundle that data into the JSON blob to be sent to the server</li>
</ul>
<p>This way there’s no need to mess with any registers. All the more reason why I2C and even SPI are better data buses than UART. I just want it to work!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/DSC01372.jpg" alt="Holding HPMA115S0" width="600" height="400" loading="lazy"></p>
<p>I originally chose this sensor a while back for it’s enclosed nature. In my option, it’s easier to integrate. My electrical engineer brain doesn’t want to deal with complex stuff. Give me a box and lets go.</p>
<h2 id="heading-getting-everything-working">Getting everything working</h2>
<p>During the development phase of this project I happened to be traveling abroad. The crappy wifi was not cutting it and it was taking forever to iterate on the code. The Argon also had a hard time connected to my iPhone’s AP so I gave up on that idea early on.</p>
<p>So, in order to develop the code that didn’t require the internet I placed the device into manual mode. What does manual mode do? It allows the code to start execution despite not being connected to the Particle cloud. That way you can take readings all day but you don’t have to be connected to Wifi.  You can put the device in manual mode by putting this define in your <code>.ino</code> file:</p>
<pre><code>SYSTEM_MODE(MANUAL);
</code></pre><p>In battery powered applications, this is ideal. Wifi is expensive power-wise and you don’t need to be running it if you don’t have to!</p>
<p>In a previous experiment, I found that it took about 10-15 seconds from nothing to sending data to the Particle cloud. That’s a <strong>long time</strong> in the embedded world. That’s one of the main reasons I suspect Particle came out with their mesh system. This allows sleepy end nodes (or nodes that are taking data and periodically sending it to a central point) to run much longer than their Wifi based cousins.</p>
<p>Remember you will have to run the <code>Particle.connect()</code> function in order to connect to wifi in manual mode. Or if you’re ready for it to re-connect, remove <code>SYSTEM_MODE(MANUAL);</code> from your <code>.ino</code> file.</p>
<h3 id="heading-changing-wifi-credentials">Changing Wifi Credentials</h3>
<p>During my experiment in trying to get my wifi to work I did discover a few handy Particle tools to change wifi credentials etc. By holding the mode button during operation, the device eventually starts blinking blue. Once blinking blue, you can issue a <code>particle serial wifi</code> which will walk you through the process of changing the credentials.</p>
<p>The above process is light years faster than using the iPhone/Android app. I thought the app was cool at first but man does it take a long time to scan and get your devices connected.</p>
<p><a target="_blank" href="https://docs.particle.io/tutorials/device-os/led/argon/#network-reset-fast-blinking-blue-">More info on this procedure go here.</a></p>
<h3 id="heading-recovering-when-things-go-awry">Recovering when things go awry</h3>
<p>I had to recover my Argon during my development process. I did some digging and found that re-programming the OS, App and Bootloader seemed to do the trick.</p>
<p>Get the files here: <a target="_blank" href="https://github.com/particle-iot/device-os/releases/tag/v0.9.0">Release 0.9.0 (Gen 3) · particle-iot/device-os · GitHub</a> (As of this writing the latest is 0.9.0)</p>
<p>Then program these files in <a target="_blank" href="https://docs.particle.io/tutorials/device-os/led/photon/#dfu-mode-device-firmware-upgrade-">DFU mode</a> by holding the <code>mode</code> button after tapping the <code>reset</code> button once.</p>
<pre><code>particle flash --usb system-part1<span class="hljs-number">-0.9</span><span class="hljs-number">.0</span>-argon.bin
particle flash --usb tinker<span class="hljs-number">-0.9</span><span class="hljs-number">.0</span>-argon.bin
</code></pre><p>Program this one in <a target="_blank" href="https://docs.particle.io/tutorials/device-os/led/photon/#listening-mode">Listening mode:</a></p>
<pre><code>particle flash --serial bootloader<span class="hljs-number">-0.9</span><span class="hljs-number">.0</span>-argon.bin
</code></pre><p><em>Note:</em> the <code>-argon</code> suffix may be different depending on what you’re programming to. Other options are <code>-boron</code> and <code>-xenon</code>.</p>
<h2 id="heading-monitoring-on-the-command-line">Monitoring on the command line</h2>
<p>Finally, one of the most useful commands is this one:</p>
<p><code>particle serial monitor --follow</code></p>
<p>This allows you to use the USB <code>Serial</code> interface to receive debug messages from he device. This is akin to connecting an FTDI device to an Arduino.</p>
<p>For instance, I may be debugging part of the code so I want to see some data. In the <code>Setup()</code> function I’ll be sure to run <code>Serial.begin()</code>, then later on I’ll make a <code>Serial.printf(“data: %d”,data.tvoc);</code> in order for it to be sent over the USB Serial interface.</p>
<p>Serial UART for debugging, it’s a beautiful thing.</p>
<h2 id="heading-publishing">Publishing</h2>
<p>One thing I did discover during the development process was the publishing limits of the Particle platform. For a single device, you cannot <code>Particle.Publish</code> more than 4 pieces of data in one second. Even though I was taking data every minute, I was sending 6 pieces of individual data to the server at the same time. After testing I soon started to wonder why the heck my C02 and TVOC readings disappeared.</p>
<p>I had found the culprit.</p>
<p>So, in order to make things work, I had to format it as a JSON blob. See how I did it exactly below:</p>
<pre><code><span class="hljs-built_in">String</span> out = <span class="hljs-built_in">String</span>::format(<span class="hljs-string">"{\"temperature\":%.2f,\"humidity\":%.2f,\"pm25\":%d,\"pm10\":%d,\"tvoc\":%d,\"c02\":%d}"</span>,si7021_data.temperature,si7021_data.humidity,hpma115_data.pm25,hpma115_data.pm10,ccs811_data.tvoc,ccs811_data.c02);
Particle.publish(<span class="hljs-string">"blob"</span>, out , PRIVATE, WITH_ACK);
</code></pre><p>I created a JSON structure and then used <code>String::format</code> to insert each piece where they needed to be. If you are running your device over LTE this will cause you to send more data than necessary. There are better options like <a target="_blank" href="https://www.jaredwolff.com/how-to-define-your-own-bluetooth-low-energy-configuration-service-using-protobuf/">Protocol Buffers</a> or using <a target="_blank" href="https://msgpack.org">MessagePack</a>. If you’re dealing with complex data, I recommend the former because of its programatic nature. Plus, you can use it with just about any programming language. So web to embedded? No problem.</p>
<p>After every minute, I only send the data when all three sensors have been read. I use three separate boolean values to determine the state of the sensor readings. Once they have all been set to <code>true</code> do I invoke the <code>Particle.Publish</code>call.</p>
<p>Then after publishing, I reset all variables like so:</p>
<pre><code>ccs811_data_ready = <span class="hljs-literal">false</span>;
si7021_data_ready = <span class="hljs-literal">false</span>;
hpma115_data_ready = <span class="hljs-literal">false</span>;
</code></pre><p>Then, everything starts all over again. You can also create a status struct which has each of these flags neatly inside. Considering I only have three data points, I didn’t go the extra mile there.</p>
<h2 id="heading-using-adafruit-io">Using Adafruit IO</h2>
<p>One way to publish is by using Adafruits IO platform. Here's how to get started.</p>
<ol>
<li>Create an account here: https://io.adafruit.com</li>
<li><p>Next is to create feeds for each of the data types. We’ll need 6 in total.
<img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-19_at_6.47.38_PM.png" alt="Create a feed in Adafruit IO" width="600" height="400" loading="lazy"></p>
</li>
<li><p>For each feed, add a Webhook.
<img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-19_at_6.45.27_PM.png" alt="Add a webhook for data" width="600" height="400" loading="lazy"></p>
</li>
<li>Take each webhook address and create a new Webhook in the Particle console</li>
<li>Change the <code>Request format</code> to JSON</li>
<li>Then under <code>Advanced Settings</code> click on <code>Custom</code> for the <strong>JSON DATA</strong></li>
<li><p>Replace what’s there using <a target="_blank" href="https://docs.particle.io/reference/device-cloud/webhooks/#variable-substitution">mustache templates</a>. Adafruit IO is looking for a JSON key called <code>value</code>. So set it like this:</p>
<pre><code>{
 “value”:”{{{c02}}}”
}
</code></pre><p>You can replace <code>c02</code> with any of the keys in your JSON blob. As a reminder the current JSON blob looks something like this:</p>
<pre><code>{
 “temperature”:<span class="hljs-number">21.2</span>,
 “humidity”:<span class="hljs-number">30</span>,
 “pm10”:<span class="hljs-number">2</span>,
 “pm25”:<span class="hljs-number">1</span>,
 “tvoc”:<span class="hljs-number">650</span>,
 “c02”:<span class="hljs-number">1001</span>
}
</code></pre></li>
<li>Repeat this as necessary until all feeds have a corresponding Webhook configured.</li>
<li>Finally, you can create a dashboard to see them all in one place. This is straight forward just follow the on screen prompts. :)</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-19_at_7.04.16_PM.png" alt="List of Feeds" width="600" height="400" loading="lazy">
<img src="https://www.freecodecamp.org/news/content/images/2020/08/Screen_Shot_2019-03-19_at_7.16.17_PM.png" alt="Graphs of Feeds" width="600" height="400" loading="lazy"></p>
<p>You can check out my <a target="_blank" href="https://io.adafruit.com/jaredwolff/dashboards/air-quality-sensor">live dashboard here</a>. It’s nifty and just another way to display your data.</p>
<p><strong>Sidenote:</strong> My first impressions on Adafruit IO are good. It was easy to setup and start using. The main drawback that it’s tedious especially if you have more than a handful of data points. But maybe they’ll fix that in the future!</p>
<p><strong>Update:</strong> If you have multiple pieces of data. You can point your Particle integration to a single endpoint. Just make sure the data is in the same group! Here's an example of multiple values sent to the same group:</p>
<pre><code>{
  <span class="hljs-string">"feeds"</span>: [
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"tvoc"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{tvoc}}}"</span>
    },
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"c02"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{c02}}}"</span>
    },
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"temperature"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{temperature}}}"</span>
    },
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"humidity"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{humidity}}}"</span>
    },
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"pm2-dot-5"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{pm25}}}"</span>
    },
    {
      <span class="hljs-string">"key"</span>: <span class="hljs-string">"pm10"</span>,
      <span class="hljs-string">"value"</span>: <span class="hljs-string">"{{{pm10}}}"</span>
    }
  ]
}
</code></pre><p>Where your URL should look something like:</p>
<pre><code>https:<span class="hljs-comment">//io.adafruit.com/api/v2/&lt;USERNAME&gt;/groups/&lt;GROUPNAME&gt;/data</span>
</code></pre><p>That should keep your Particle integration page a little more sane!</p>
<h2 id="heading-making-sense-of-the-readings">Making sense of the readings</h2>
<p>The readings can be confusing. Here’s the breakdown of how they work:</p>
<ol>
<li>Humidity is showing in relative percentage points. This is the relative humidity we know and love. Remember it may differ with what’s outside. This depends on if your house is air conditioned or if you’re running a heater etc.</li>
<li>Temperature is in degrees C (can be modified in firmware if you so choose)</li>
<li>TVOC is in ppb (parts per billion). VOCs can be in the form of harmful chemicals you have around the house. More information about VOCs check out this<a target="_blank" href="https://www.epa.gov/indoor-air-quality-iaq/volatile-organic-compounds-impact-indoor-air-quality">link from the EPA</a>.</li>
<li>C02 is in ppm (parts per million). We breathe in oxygen and exhale carbon dioxide. You may find your VOC and C02 levels rising when you’re in the room. C02 does correlate to VOCs as well. <a target="_blank" href="https://ams.com/documents/20143/36005/CCS811_DS000459_7-00.pdf">More info in the data sheet.</a></li>
<li>PM10. Is in µg/m3 (micrograms per meter cubed). The particle sensor uses a scattered laser when then shines across the air chamber to a sensor on the other side. The more the rays are blocked, the more particles in the air. The particle sensor then does some calculations to determine the amount of particles in a certain volume and thus your µg/m3.</li>
<li>PM2.5 is the same as above but it tracks much smaller particles. (Less than or equal to 2.5µm in size!) <a target="_blank" href="https://www.epa.gov/pm-pollution/particulate-matter-pm-basics">More information on the EPA’s website here.</a></li>
</ol>
<h2 id="heading-dont-care-for-something-you-have-no-control-over">Don't care for something you have no control over?</h2>
<p><a target="_blank" href="https://www.jaredwolff.com/how-to-make-an-amazing-looking-iot-dashboard-in-no-time/">Check out my tutorial on creating your own amazing looking IoT dashboard.</a></p>
<h2 id="heading-you-did-it">You did it!</h2>
<p>Congrats. You've made it this far. You deserve a day at the spa. Or maybe some chocolate ice cream. Or if you're really feeling adventurous, both, at the same time?? ?</p>
<p>After building one of these you may feel like your time is worth investing elsewhere. Maybe you want to build a cool web backend with fancier charts and algorithms. Maybe even use some machine learning (why not!)</p>
<p>If you want something already assembled and available you should check out the Particle^2 (Pronounced Particle Squared). It has everything here including the ability to switch on and off the HPM particle sensor. You can even run it on batteries! So put that sucker anywhere you want. <a target="_blank" href="https://www.jaredwolff.com/store/particle-squared/">Check it out here.</a></p>
<p>Here's the full video on the Particle Squared.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/IR2W0GmRKk8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-code-and-source">Code and Source</h2>
<p>This whole project is released under the Creative Commons Share-Alike license. <a target="_blank" href="https://www.jaredwolff.com/files/air-quality/#main">Get the source code and hardware files here.</a></p>
<h2 id="heading-get-ready-for-the-ultimate-guide">Get Ready for the Ultimate Guide</h2>
<p>This post is an excerpt from my upcoming Ultimate Guide on Particle Mesh. Early subscribers get a discount when it becomes available! <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">Click here to get signed up.</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
