Mendes
Mendes

Reputation: 18551

How to print a single div of a react deep structure

I'm trying to print a single area using React. I've build a simple component Print:

import React, { Component } from "react";

class Print extends Component {

    render = () => {
        return (
                <div id="printable-area">
                    {this.props.children}
                </div>
                );
    }
}

export default Print;

Add added the following stype to the topmost div of my application:

// Body
html {
    box-sizing: border-box;
}

*,
*:before,
*:after {
    box-sizing: inherit;
}

body {
    font-family: $default-font;
    font-weight: normal;
    font-size: 14px;
    color: $ux-theme-color-dark;
    margin: 0px !important;
    padding: 0px !important;
    background-color: $ux-theme-color-background;
}

// Print contol (A4)
@media print {
    body * {
        display: none;
    }
    #printable-area {
        display: block;
    }
}

No matter where in my component tree I put my Print component, nothing is being printed (always an empty page):

... several components
   <Print>
     ... printable components
   </Print>
... several components

What am I missing here?

Upvotes: 2

Views: 4449

Answers (2)

KevBot
KevBot

Reputation: 18908

The Problem:

If you remove the @media print { rule to see what the styles would appear as when that rule is applied by the browser, you can see that the parent(s) of the printable area is hiding the actual printable area. If the parent is set to display none, then any child cannot show.

/* @media print { */

body * {
  display: none;
}

#printable-area {
  display: block;
}


/* } */
<div>
  You can't see this.
  <div id="printable-area">Printable Area (You can't see this either)</div>
</div>

A basic solution:

For this solution, you will need to traverse up the parent structure for the printable area and add some additional classNames:

/* @media print { */

body> :not(.print-parent):not(.print-me) {
  display: none;
}

.print-parent> :not(.print-parent):not(.print-me) {
  display: none;
}


/* } */
<div class="print-parent">
  <div>This should not print</div>
  <div class="print-parent">
    <div class="print-me">Print just this!</div>
  </div>
</div>

Upvotes: 2

Aaronius
Aaronius

Reputation: 4953

There's probably an ancestor of your #printable-area div that's getting hidden by the body * rule. Even if your #printable-area div has display: block, it will still not be displayed if one of its containing elements is hidden.

Upvotes: 0

Related Questions