Bootstrap card in react - reactjs

I'm suffering from implementing bootstrap in react. I set up bootstrap4 at the beginning but I got a bad layout then used react-bootstrap and I get the same issue. Th card body,title and button appear on the image itselfenter image description here
import React from 'react';
import { Card, Button } from 'react-bootstrap';
const WorkCard = () => {
return (
<div>
<Card style={{ width: '18rem' }} >
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>Card Title</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up the bulk of
the card's content.
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card >
</div>
)
}
export default WorkCard;

Using sass was overriding the bootstrap so I fixed that.

Related

How do I use Bootstrap grid with components in react?

I want to get at least 2 cards on the same row but since the data is getting mapped one by one, I have no idea how to do so. I am using a custom component named 'Content' and returning data here
import React from "react";
import { Card, CardGroup, Col, Row } from "react-bootstrap";
import { ListGroup, ListGroupItem } from "react-bootstrap";
const Content=({name, image, type, vegan, cuisines})=>{
return(
<div>
<CardGroup>
<Col xs={12} sm={6} md={4} lg={4}>
<Card>
<Card.Img variant="top" src={image} />
<Card.Body>
<Card.Title>{name}</Card.Title>
<Card.Text>
<ListGroup>
<ListGroupItem>Type: {type}</ListGroupItem>
<ListGroupItem>Vegan: {vegan}</ListGroupItem>
<ListGroupItem>Cuisines: {cuisines.cuisines.join(", ")}</ListGroupItem>
</ListGroup>
</Card.Text>
</Card.Body>
</Card>
</Col>
</CardGroup>
</div>
)
}
export default Content
I believe you aren't using the Row component to wrap your columns.
Try replacing <CardGroup> with <Row> as shown in this section of the docs.

How to replace Panel Component with Card Component in React

I have updated bootstrap from v3.X.x to v4.x.x and react-bootstrap to 0.32.X to 1.4.0, now I am facing issue with the panel component.
As per bootstrap documentation Panel component is removed from latest bootstrap and can be replaced by Card component.
Anyone help me out to update below panel component with Card Component
This is my existing code:
import * as React from 'react';
import { Panel } from 'react-bootstrap';
<Panel>
<Panel.Heading style={{ padding: "10px" }}>
<Panel.Title componentClass="h3" toggle>
Panel Test
</Panel.Title>
</Panel.Heading>
<Panel.Collapse>
<Panel.Body>
<p> Test Body </p>
</Panel.Body>
</Panel.Collapse>
</Panel>
Card.Heading and Card.Collapse is not available at the moment other code we can replace with Card like Card.Body or Card.Title
This is how the components are replaced. For Collapsing I have used Accordian
Panel -> Card
Panel.Heading -> Card.Header
Panel.Title -> Card.Title
Panel.Collapse -> Accordion.Collapse
attribute componentClass is renamed as as
This is final code
import * as React from 'react';
import { Card, Accordion } from 'react-bootstrap';
<Accordion defaultActiveKey="0">
<Card>
<Accordion.Toggle as={Card.Header} variant="link" eventKey="0" style={{ padding: "10px" }}>
<Card.Title as="h3" toggle>
Panel Test
</Card.Title>
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<p> Test Body </p>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
I am sorry i did not notice that but you can achieve the same effect with react-bootstrap's accordion collapse, you can include that in your card component,
Link to the collapse accordion : https://react-bootstrap.netlify.app/components/accordion/#accordion-collapse-props

How do you render an image with Card.Img in React Bootstrap and Gatsby?

I created a component that makes a Card with a photo and text inside the image, however, I get the alt text when rendering the <Card.Img> tag but displays the image to the site. Should I just use src or is there a way to use fluid?
const Page = ({ title, subtitle, path, date, body, image}) => {
return(
<Card>
<Card.Img fluid={image} alt="Card image" />
<Card.ImgOverlay>
<Card.Title> {title} </Card.Title>
<Card.Subtitle> {subtitle} </Card.Subtitle>
<Card.Subtitle> {path} </Card.Subtitle>
<Card.Subtitle> {date} </Card.Subtitle>
<Card.Body> {body} </Card.Body>
<Img fluid={image} />
</Card.ImgOverlay>
</Card>
)
}
export default Page
Card.Img does not have a fluid prop by default, but the Image component does. Also, take note that fluid accepts a boolean value, not an image source. You can use the as prop of the Card.Img component to use a custom component Image if you must use the fluid properties.
import { Image } from "react-bootstrap";
<Card.Img as={Image} src={image} fluid={true} alt="Card image" />
An alternate solution would be to just include the class of img-fluid to the Card.Img
<Card.Img src={image} className="img-fluid" alt="Card image" />
To use the <Img> component from gatsby-image your need to query the data using the childImageSharp GraphQL fragment or an alternative approach to fetch all the needed data. In your case, I assume that the image prop only contains the source of the image, not all the data from the query fragment itself that's why your image is not showing.
Without seeing your query, you have three workarounds:
Use the native HTML <img> tag:
<Card.ImgOverlay>
<Card.Title> {title} </Card.Title>
<Card.Subtitle> {subtitle} </Card.Subtitle>
<Card.Subtitle> {path} </Card.Subtitle>
<Card.Subtitle> {date} </Card.Subtitle>
<Card.Body> {body} </Card.Body>
<img src={image} alt={`Your alt text`}/>
</Card.ImgOverlay>
Use the <Card.Img> component from React Boostrap:
<Card.ImgOverlay>
<Card.Title> {title} </Card.Title>
<Card.Subtitle> {subtitle} </Card.Subtitle>
<Card.Subtitle> {path} </Card.Subtitle>
<Card.Subtitle> {date} </Card.Subtitle>
<Card.Body> {body} </Card.Body>
<Card.Img src={image} alt={`Your alt text`}/>
</Card.ImgOverlay>
Use the GraphQL query fragment to retrieve all the needed data to use gatsby-image properly. An ideal approach should look like:
import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image"
export default ({ data }) => (
<div>
<h1>Hello gatsby-image</h1>
<Img fluid={data.file.childImageSharp.fluid} />
</div>
)
export const query = graphql`
query {
file(relativePath: { eq: "your/path/to/image.jpeg" }) {
childImageSharp {
# Specify the image processing specifications right in the query.
# Makes it trivial to update as your page's design changes.
fluid(width: 125) {
...GatsbyImageSharpFluid
}
}
}
}
`
Note that you may need to adapt the snippet above to your component, specifications, and requirements.
As you can see, the GraphQL query above contains the ...GatsbyImageSharpFluid fragment (that is exactly the same to get one by one all the properties from the image). Now, your data object contains all the data needed to use the <Img> component and you can use the fluid prop with <Img fluid={data.file.childImageSharp.fluid} />
You can check for further details in the Gatsby Image documentation

React Bootstrap Cards and CardDeck Components - responsive layout

I'm using React Bootstrap and am pulling data from an API using Axios. I'm trying to display the data from that API in bootstrap Card / CarDeck components. I have most of it working using the code below but I'm having problems with the layout.
I'd like to be able to have the card deck be responsive and show a flexible number of cards per row depending on the screen size. At the moment if there are lots of items in the response each card is ridiculously thin and can't be viewed. What is the correct way to do this?
import React, { useState, useEffect } from "react";
import CardDeck from "react-bootstrap/CardDeck";
import Card from "react-bootstrap/Card";
import axios from "axios";
import Container from "react-bootstrap/Container";
const CardColumns = () => {
const [cardInfo, setData] = useState([]);
console.log(cardInfo);
useEffect(() => {
axios
.get(
"https://webhooks.mongodb-realm.com/api/client/v2.0/app/cards-fvyrn/service/Cards/incoming_webhook/getAllCards"
)
.then((response) => {
setData(response.data);
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}, []);
const renderCard = (card, index) => {
return (
<Card style={{ width: "18rem" }} key={index} className="box">
<Card.Img variant="top" src="holder.js/100px180" src={card.image} />
<Card.Body>
<Card.Title>
{index} - {card.manufacturer}
</Card.Title>
<Card.Text>{card.player}</Card.Text>
</Card.Body>
</Card>
);
};
return <CardDeck>{cardInfo.map(renderCard)}</CardDeck>;
};
export default CardColumns;
In the end this is the solution I went with the below. Key I think were:
Wrapping the cardDeck in <Container> and then wrapping the cards with <Col className="container-fluid mt-4">:
`
const renderCard = (card, index) => {
return (`
<Col className="container-fluid mt-4">
{/* <Card key={index} className="box"> */}
<Card style={{ width: "18rem" }} key={index} className="box">
<Card.Header>
{card.brand} - {card.series}
</Card.Header>
<Card.Img variant="top" src={card.front_image} fluid />
<Card.Body>
<Card.Title>
{card.player} (#
{card.card_number.$numberDouble}) {card.variation}
</Card.Title>
{/* <Card.Text className="d-flex">{card.player}</Card.Text> */}
{/* <Card.Text>{card.player}</Card.Text> */}
</Card.Body>
<ListGroup className="list-group-flush">
<ListGroupItem>
Print Run - {card.print_run.$numberDouble}
</ListGroupItem>
<ListGroupItem>Career Stage - {card.career_stage} </ListGroupItem>
<ListGroupItem>For Trade - {card.forTrade}</ListGroupItem>
</ListGroup>
<Card.Footer className="text-muted">{card.team}</Card.Footer>
</Card>
</Col>
//{/* </Col> */}
);
};
return (
<Container>
<Button variant="primary">Filter By Brand</Button>{" "}
<Button variant="primary">Filter By Player</Button>{" "}
<Button variant="primary">Filter By Team</Button>
<CardDeck>{cardInfo.map(renderCard)}</CardDeck>
</Container>
);`
Here are my suggestions for this issue:
Each card should have a min-width to ensure that they do not shrink below a certain amount. So instead of width: "18rem" try min-width: "18rem". If your CSS is properly set up it should cause other cards to overflow to the next row.
You can make use of media-queries or grid layout as mentioned to determine how many cards you want to show for various screen types based on their varying widths say see this link media-query-breakpoints react-bootstrap-grid
Also you can try using CSS flexbox layout, I have an article on this CSS Flex Box
Try to use a col-'n' to each card instead of a fix width.
...
import { Card, Col } from 'react-bootstrap';
...
<Col md="n"> // n must be your desired width like
<Card key={index} className="box">
...
</Col>
You can see more at: Bootstrap Card Sizing

How can I render <Card.Text> as <div> element and not as <p>?

For <Card.Body> there seems to be a parameter named as which is of type elementType and defaults to <div>.
https://react-bootstrap.github.io/components/cards/#card-body-props
Now <Card.Text> defaults to <p> which results in warnings on my website as I have nested <div> elements inside <Card.Text>
Warning: validateDOMNesting(...): cannot appear as a descendant of <p>
So basically two questions:
How can I change/set the elementtype on Card.Body? The following attempts did not get reflected in the produced html (checked with Chrome DevTools): <Card.Body as="p">...</Card.Body> nor did this <Card.Body as="<p>">...</Card.Body>
How can I change the elementtype on <Card.Text>?
This is what my component looks like
import React from "react"
import { Link } from "gatsby"
import Img from "gatsby-image"
import Card from "react-bootstrap/Card"
import Tags from "./tags"
import TimeToRead from "./time-to-read"
const Post = ({ title, slug, date, body, fluid, tags, timeToRead }) => {
return (
<Card className="mb-3 shadow-lg" bg="concrete" id="hoverable">
<Link to={slug}>
<Img
className="card-image-top"
style={{ maxHeight: "150px" }}
fluid={fluid}
></Img>
<Card.ImgOverlay
style={{
pointerEvents: "none",
}}
>
<Tags tags={tags} />
</Card.ImgOverlay>
</Link>
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Subtitle>
<div className="d-flex justify-content-between">
<span className="text-info">{date}</span>
<TimeToRead minutes={timeToRead} />
</div>
</Card.Subtitle>
<hr />
<Card.Text as="div">{body}</Card.Text>
<Link
to={slug}
className="btn btn-outline-primary float-right text-uppercase"
>
Read more
</Link>
</Card.Body>
</Card>
)
}
export default Post
I had the same problem, essentially. I used an unordered list inside the text for the <Card.Body> and the console displayed the following warning:
validateDOMNesting(...): <ul> cannot appear as descendent of <p>.
Wrapping the list content inside a <div> just added to the warning list. As suggested above, I amended the <Card.Text> tag, but as follows:
<Card.Text as="div">
The warning disappeared and the text renders. Note, you have to adjust the styling, depending on how the styling cascade is configured.

Resources