Progress
Custom progress bars featuring support for stacked bars, animated backgrounds, and text labels.
Color variations (thick)
import Stack from 'react-bootstrap/Stack'
import ProgressBar from 'react-bootstrap/ProgressBar'
export default function ProgressThickDemo() {
return (
<Stack direction="vertical" gap={3}>
{[
{ variant: 'primary', value: 45 },
{ variant: 'success', value: 55 },
{ variant: 'danger', value: 40 },
{ variant: 'warning', value: 70 },
{ variant: 'info', value: 60 },
].map(({ variant, value }, index) => (
<ProgressBar
key={index}
variant={variant}
now={value}
label={`${value}%`}
aria-label={`Progress ${variant}`}
/>
))}
<ProgressBar
variant="dark"
now={33}
label="33%"
className="d-none-dark"
aria-label="Progress dark"
/>
<ProgressBar
variant="light"
now={33}
label="33%"
className="d-none d-flex-dark"
aria-label="Progress light"
/>
</Stack>
)
}
Color variations (thin)
45%
55%
40%
70%
60%
33%
import Stack from 'react-bootstrap/Stack'
import ProgressBar from 'react-bootstrap/ProgressBar'
export default function ProgressThinDemo() {
return (
<Stack direction="vertical" gap={3}>
{[
{ variant: 'primary', value: 45 },
{ variant: 'success', value: 55 },
{ variant: 'danger', value: 40 },
{ variant: 'warning', value: 70 },
{ variant: 'info', value: 60 },
].map(({ variant, value }, index) => (
<div key={index}>
<div className="fs-sm mb-2">{value}%</div>
<ProgressBar variant={variant} now={value} style={{ height: 4 }} aria-label={`Progress ${variant}`} />
</div>
))}
<div>
<div className="fs-sm mb-2">33%</div>
<ProgressBar
variant="dark"
now={33}
style={{ height: 4 }}
className="d-none-dark"
aria-label="Progress dark"
/>
<ProgressBar
variant="light"
now={33}
style={{ height: 4 }}
className="d-none d-flex-dark"
aria-label="Progress light"
/>
</div>
</Stack>
)
}
Multiple bars
import ProgressBar from 'react-bootstrap/ProgressBar'
export default function ProgressMultipleBarsDemo() {
return (
<>
<ProgressBar className="mb-3">
<ProgressBar variant="primary" now={15} aria-label="Segment one" />
<ProgressBar variant="success" now={10} aria-label="Segment two" />
<ProgressBar variant="info" now={20} aria-label="Segment three" />
<ProgressBar variant="warning" now={25} aria-label="Segment four" />
</ProgressBar>
<ProgressBar style={{ height: 4 }}>
<ProgressBar variant="warning" now={25} aria-label="Segment one" />
<ProgressBar variant="success" now={15} aria-label="Segment two" />
<ProgressBar variant="primary" now={20} aria-label="Segment three" />
<ProgressBar variant="info" now={10} aria-label="Segment four" />
</ProgressBar>
</>
)
}
Animated striped bars
import Stack from 'react-bootstrap/Stack'
import ProgressBar from 'react-bootstrap/ProgressBar'
export default function ProgressAnimatedStripedDemo() {
return (
<Stack direction="vertical" gap={3}>
{[
{ variant: 'primary', value: 45 },
{ variant: 'success', value: 55 },
{ variant: 'danger', value: 40 },
{ variant: 'warning', value: 70 },
{ variant: 'info', value: 60 },
].map(({ variant, value }, index) => (
<ProgressBar
key={index}
variant={variant}
animated
now={value}
aria-label={`Progress ${variant}`}
/>
))}
<ProgressBar
variant="dark"
animated
now={33}
className="d-none-dark"
aria-label="Progress dark"
/>
<ProgressBar
variant="light"
animated
now={33}
className="d-none d-flex-dark"
aria-label="Progress light"
/>
</Stack>
)
}
Use case: Rating breakdown
4.2
68 reviews
5
37
4
16
3
8
2
4
1
3
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import ProgressBar from 'react-bootstrap/ProgressBar'
import Stack from 'react-bootstrap/Stack'
import StarRating from '@/components/reviews/star-rating'
export default function ProgressRatingBreakdownDemo() {
const ratings = [
{ ratingNumber: 5, ratingLabel: 'Five', quantity: 37 },
{ ratingNumber: 4, ratingLabel: 'Four', quantity: 16 },
{ ratingNumber: 3, ratingLabel: 'Three', quantity: 8 },
{ ratingNumber: 2, ratingLabel: 'Two', quantity: 4 },
{ ratingNumber: 1, ratingLabel: 'One', quantity: 3 },
]
const totalQuantity = ratings.reduce((sum, { quantity }) => sum + quantity, 0)
const weightedSum = ratings.reduce((sum, { ratingNumber, quantity }) => sum + ratingNumber * quantity, 0)
const averageRating = (weightedSum / totalQuantity).toFixed(1)
return (
<Row className="g-4">
<Col sm={5} md={3}>
<div className="d-flex flex-column align-items-center justify-content-center h-100 bg-body-tertiary rounded p-4">
<div className="h1 pb-2 mb-1">{averageRating}</div>
<StarRating rating={averageRating} className="fs-sm mb-2" />
<div className="fs-sm">{totalQuantity} reviews</div>
</div>
</Col>
<Col sm={7} md={9}>
<Stack direction="vertical" gap={3}>
{ratings.map(({ ratingNumber, ratingLabel, quantity }) => (
<Stack key={ratingNumber} direction="horizontal" gap={2} className="fs-sm">
<Stack direction="horizontal" gap={1}>
{ratingNumber}
<i className="ci-star-filled text-warning"/>
</Stack>
<ProgressBar
variant="warning"
now={(quantity / totalQuantity) * 100}
className="w-100"
style={{ height: 4 }}
aria-label={`${ratingLabel} stars`}
/>
<div className="text-nowrap text-end" style={{ width: 40 }}>
{quantity}
</div>
</Stack>
))}
</Stack>
</Col>
</Row>
)
}