1 - Basic Setup
1.5 Finalizing Card Style

Final NoteCard Styling

We've already added some basic stying to our note card component, but now it's time to add the final touches.

Body styling

  • Inside of the card component, add another div around {body} and give this dive the class name of card-body
  • Within the card body div, add a <textarea> and pass in the the values shown below.
NoteCard.jsx
<div className="card"
    //...
    >
 
    <div className="card-body">
        <textarea
            style={{ color: colors.colorText }}
            defaultValue={body}
        ></textarea>
    </div>
 
</div>

Add the following styles in index.css

index.css
.card-body {
    padding: 1em;
    border-radius: 0 0 5px 5px;
}
 
.card-body textarea {
    background-color: inherit;
    border: none;
    width: 100%;
    height: 100%;
    resize: none;
    font-size: 16px;
}
 
textarea:focus {
    background-color: inherit;
    outline: none;
    width: 100%;
    height: 100%;
}

Header Styling

Each card will have it's own header bar. This will sit within our card component, above card-body

NoteCard.jsx
<div className="card" 
    //...
    >
 
    <div
        className="card-header"
        style={{ backgroundColor: colors.colorHeader }}
    ></div>
 
    <div className="card-body">
    
</div>

Card header styling: index.css

index.css
.card-header {
    background-color: #9bd1de;
    border-radius: 5px 5px 0 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px;
}

Create a trash Icon in src/icons/Trash.jsx

Trash.jsx
const Trash = ({ size = "24" }) => {
    return (
        <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width={size}
            height={size}
            stroke="#000000"
            fill="none"
            strokeWidth="1.5"
        >
            <path d="m6 8 .668 8.681c.148 1.924.222 2.885.84 3.423.068.06.14.115.217.165.685.449 1.63.26 3.522-.118.36-.072.54-.108.721-.111h.064c.182.003.361.039.72.11 1.892.379 2.838.568 3.523.12.076-.05.15-.106.218-.166.617-.538.691-1.5.84-3.423L18 8"></path>
            <path
                strokeLinecap="round"
                d="m10.151 12.5.245 3.492M13.849 12.5l-.245 3.492M4 8s4.851 1 8 1 8-1 8-1M8 5l.447-.894A2 2 0 0 1 10.237 3h3.527a2 2 0 0 1 1.789 1.106L16 5"
            ></path>
        </svg>
    );
};

Import the new <Icon/> component into the <NoteCard/> header.

NoteCard.jsx
<div className="card-header" 
        //....
        >
    <Trash />
</div>

Absolute Positioning

Each card will have its own unique position and can be placed anywhere on our page. To accomplish this, we will give every card an absolute position and then utilize the position x and y values to set this in the styles.

index.css
.card {
    /* ... */
    position: absolute;
}
NoteCard.jsx
const NoteCard = ({ note }) => {
    //...
    return (
        <div
            className="card"
            style={{
                backgroundColor: colors.colorBody,
                left: `${position.x}px`,
                top: `${position.y}px`,
            }}
        >
        //...

Autogrow text field

Because there is not predetermined height for each card, we will auto adjust the card size based on the contents within the text area.

By using a ref we will access the textarea and auto grow the height when the card is rendered, by calling this inside of the useEffect hook.

const textAreaRef = useRef(null);
 
//...
 
<textarea
    ref={textAreaRef}

Create and call function

NoteCard.jsx
useEffect(() => {
    autoGrow(textAreaRef);
}, []);
 
function autoGrow(textAreaRef) {
    const { current } = textAreaRef;
    current.style.height = "auto"; // Reset the height
    current.style.height = current.scrollHeight + "px"; // Set the new height
}

We want the text area to grow OR shrink anytime we make add or remove values as well.

 onInput={() => {
     autoGrow(textAreaRef);
}}