MeterGroup

MeterGroup displays scalar measurements within a known range.

Usage#

import { MeterGroup } from 'primereact/metergroup';
<MeterGroup>
    <MeterGroup.Meters>
        <MeterGroup.Meter value={value} color={color} />
    </MeterGroup.Meters>
    <MeterGroup.Labels>
        <MeterGroup.Label>
            <MeterGroup.Marker color={color} />
            <MeterGroup.Text>Value</MeterGroup.Text>
        </MeterGroup.Label>
    </MeterGroup.Labels>
</MeterGroup>

Examples#

Basic#

MeterGroup consists of MeterGroup.Meters and MeterGroup.Labels components. Data is displayed in the MeterGroup.Meter component using the value and color properties.

  1. Space used (15%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function BasicDemo() {
    const value = { label: 'Space used', value: 15, color: 'var(--p-primary-color)' };
 
    return (
        <div className="card">
            <MeterGroup>
                <MeterGroup.Meters>
                    <MeterGroup.Meter value={value.value} color={value.color} />
                </MeterGroup.Meters>
                <MeterGroup.Labels>
                    <MeterGroup.Label>
                        <MeterGroup.Marker color={value.color} />
                        <MeterGroup.Text>
                            {value.label} ({value.value}%)
                        </MeterGroup.Text>
                    </MeterGroup.Label>
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Multiple#

Adding more MeterGroup.Meter components displays the meters in a group. Pass index to MeterGroup.Meter and MeterGroup.Marker to identify the meter's and label's position to get the color.

  1. Apps (14%)
  2. Messages (12%)
  3. Media (8%)
  4. System (12%)
  5. Documents (6%)
  6. Cache (11%)
  7. Other (9%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function MultipleDemo() {
    const values = [
        { label: 'Apps', value: 14 },
        { label: 'Messages', value: 12 },
        { label: 'Media', value: 8 },
        { label: 'System', value: 12 },
        { label: 'Documents', value: 6 },
        { label: 'Cache', value: 11 },
        { label: 'Other', value: 9 }
    ];
 
    return (
        <div className="card">
            <MeterGroup>
                <MeterGroup.Meters>
                    {values.map((item, index) => (
                        <MeterGroup.Meter key={`meter_${index}`} index={index} value={item.value} />
                    ))}
                </MeterGroup.Meters>
                <MeterGroup.Labels>
                    {values.map((item, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            <MeterGroup.Marker index={index} />
                            <MeterGroup.Text>
                                {item.label} ({item.value}%)
                            </MeterGroup.Text>
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Color#

MeterGroup.Meter and MeterGroup.Marker components supports custom color values. Use color property or pass color with className or style. color has custom color names like blue, emerald, violet, amber, etc. or hex, rgb, hsl, or hsla values.

  1. Violet
  2. Emerald
  3. Rose
  4. Blue
  5. Yellow
import { MeterGroup } from 'primereact/metergroup';
 
export default function ColorDemo() {
    return (
        <div className="card">
            <MeterGroup>
                <MeterGroup.Meters>
                    <MeterGroup.Meter value={12} color="violet" />
                    <MeterGroup.Meter value={14} color="#10B981" />
                    <MeterGroup.Meter value={10} color="rgb(244, 63, 94)" />
                    <MeterGroup.Meter value={8} className="bg-blue-500" />
                    <MeterGroup.Meter value={10} style={{ backgroundColor: '#EAB308' }} />
                </MeterGroup.Meters>
                <MeterGroup.Labels>
                    <MeterGroup.Label>
                        <MeterGroup.Marker color="violet" />
                        <MeterGroup.Text>Violet</MeterGroup.Text>
                    </MeterGroup.Label>
                    <MeterGroup.Label>
                        <MeterGroup.Marker color="#10B981" />
                        <MeterGroup.Text>Emerald</MeterGroup.Text>
                    </MeterGroup.Label>
                    <MeterGroup.Label>
                        <MeterGroup.Marker color="rgb(244, 63, 94)" />
                        <MeterGroup.Text>Rose</MeterGroup.Text>
                    </MeterGroup.Label>
                    <MeterGroup.Label>
                        <MeterGroup.Marker className="bg-blue-500" />
                        <MeterGroup.Text>Blue</MeterGroup.Text>
                    </MeterGroup.Label>
                    <MeterGroup.Label>
                        <MeterGroup.Marker style={{ backgroundColor: '#EAB308' }} />
                        <MeterGroup.Text>Yellow</MeterGroup.Text>
                    </MeterGroup.Label>
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Icon#

Icons can be displayed next to the labels instead of the default MeterGroup.Marker.

  1. Apps (16%)
  2. Messages (8%)
  3. Media (24%)
  4. System (10%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function IconDemo() {
    const values = [
        { label: 'Apps', value: 16, icon: 'pi pi-table' },
        { label: 'Messages', value: 8, icon: 'pi pi-inbox' },
        { label: 'Media', value: 24, icon: 'pi pi-image' },
        { label: 'System', value: 10, icon: 'pi pi-cog' }
    ];
 
    return (
        <div className="card">
            <MeterGroup>
                <MeterGroup.Meters>
                    {values.map(({ value }, index) => (
                        <MeterGroup.Meter key={`meter_${index}`} value={value} index={index} />
                    ))}
                </MeterGroup.Meters>
                <MeterGroup.Labels>
                    {values.map(({ value, label, icon }, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            <MeterGroup.Icon className={icon} index={index} />
                            <MeterGroup.Text>
                                {label} ({value}%)
                            </MeterGroup.Text>
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Label#

The default orientation of the labels is horizontal, and the vertical alternative is available through the orientation option.

  1. Apps (16%)
  2. Messages (8%)
  3. Media (24%)
  4. System (10%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function LabelDemo() {
    const values = [
        { label: 'Apps', value: 16, icon: 'pi pi-table' },
        { label: 'Messages', value: 8, icon: 'pi pi-inbox' },
        { label: 'Media', value: 24, icon: 'pi pi-image' },
        { label: 'System', value: 10, icon: 'pi pi-cog' }
    ];
 
    return (
        <div className="card">
            <MeterGroup>
                <MeterGroup.Labels orientation="vertical">
                    {values.map((item, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            <MeterGroup.Marker index={index} />
                            <MeterGroup.Text>
                                {item.label} ({item.value}%)
                            </MeterGroup.Text>
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
                <MeterGroup.Meters>
                    {values.map((item, index) => (
                        <MeterGroup.Meter key={`meter_${index}`} value={item.value} index={index} />
                    ))}
                </MeterGroup.Meters>
            </MeterGroup>
        </div>
    );
}

Vertical#

Layout of the MeterGroup is configured with the orientation property that accepts either horizontal or vertical as available options.

  1. Apps (24%)
  2. Messages (16%)
  3. Media (24%)
  4. System (12%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function VerticalDemo() {
    const values = [
        { label: 'Apps', value: 24 },
        { label: 'Messages', value: 16 },
        { label: 'Media', value: 24 },
        { label: 'System', value: 12 }
    ];
 
    return (
        <div className="card flex justify-center" style={{ height: '360px' }}>
            <MeterGroup orientation="vertical">
                <MeterGroup.Meters>
                    {values.map((item, index) => (
                        <MeterGroup.Meter key={index} value={item.value} index={index} />
                    ))}
                </MeterGroup.Meters>
                <MeterGroup.Labels orientation="vertical">
                    {values.map((item, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            <MeterGroup.Marker index={index} />
                            <MeterGroup.Text>
                                {item.label} ({item.value}%)
                            </MeterGroup.Text>
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Min-Max#

Boundaries are configured with the min and max values whose defaults are 0 and 100 respectively.

  1. Apps (8%)
  2. Messages (4%)
  3. Media (12%)
  4. System (5%)
import { MeterGroup } from 'primereact/metergroup';
 
export default function MinMaxDemo() {
    const values = [
        { label: 'Apps', value: 16 },
        { label: 'Messages', value: 8 },
        { label: 'Media', value: 24 },
        { label: 'System', value: 10 }
    ];
 
    const percent = (meter: number) => {
        return Math.round(Math.max(0, Math.min(100, (meter / 200) * 100))) + '%';
    };
 
    return (
        <div className="card">
            <MeterGroup max={200}>
                <MeterGroup.Meters>
                    {values.map((item, index) => (
                        <MeterGroup.Meter key={`meter_${index}`} value={item.value} index={index} />
                    ))}
                </MeterGroup.Meters>
                <MeterGroup.Labels>
                    {values.map((item, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            <MeterGroup.Marker index={index} />
                            <MeterGroup.Text>
                                {item.label} ({percent(item.value)})
                            </MeterGroup.Text>
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
            </MeterGroup>
        </div>
    );
}

Template#

MeterGroup provides templating support for labels, meter items, and content around the meters.

Storage70%1TB
import { MeterGroup } from 'primereact/metergroup';
 
export default function TemplateDemo() {
    const values = [
        { label: 'Apps', color1: '#34d399', color2: '#fbbf24', value: 25, icon: 'pi pi-table' },
        { label: 'Messages', color1: '#fbbf24', color2: '#60a5fa', value: 15, icon: 'pi pi-inbox' },
        { label: 'Media', color1: '#60a5fa', color2: '#c084fc', value: 20, icon: 'pi pi-image' },
        { label: 'System', color1: '#c084fc', color2: '#c084fc', value: 10, icon: 'pi pi-cog' }
    ];
 
    const totalPercent = values.reduce((acc, value) => acc + value.value, 0);
 
    const percent = (meter: number) => {
        return Math.round(Math.max(0, Math.min(100, (meter / 100) * 100))) + '%';
    };
 
    return (
        <div className="card">
            <MeterGroup max={200} aria-valuenow={totalPercent}>
                <MeterGroup.Labels>
                    {values.map((value, index) => (
                        <MeterGroup.Label key={`label_${index}`}>
                            {/* <Card className="flex-1 border border-surface shadow-none">
                                <div className="flex justify-between gap-8">
                                    <div className="flex flex-col gap-1">
                                        <span className="text-surface-500 dark:text-surface-400 text-sm">{value.label}</span>
                                        <span className="font-bold text-lg">{value.value}%</span>
                                    </div>
                                    <span className="w-8 h-8 rounded-full inline-flex justify-center items-center text-center" style={{ backgroundColor: `${value.color1}`, color: '#ffffff' }}>
                                        <i className={value.icon} />
                                    </span>
                                </div>
                            </Card> */}
                        </MeterGroup.Label>
                    ))}
                </MeterGroup.Labels>
                <div className="flex justify-between mt-4 mb-2 relative">
                    <span>Storage</span>
                    <span style={{ width: totalPercent + '%' }} className="absolute text-right">
                        {totalPercent}%
                    </span>
                    <span className="font-medium">1TB</span>
                </div>
 
                <MeterGroup.Meters>
                    {values.map((item, index) => (
                        <MeterGroup.Meter
                            key={`meter_${index}`}
                            value={item.value}
                            style={{
                                background: `linear-gradient(to right, ${item.color1}, ${item.color2})`,
                                width: percent(item.value)
                            }}
                        ></MeterGroup.Meter>
                    ))}
                </MeterGroup.Meters>
                {/* <div className="flex justify-between mt-4">
                    <Button label="Manage Storage" outlined size="small" />
                    <Button label="Update Plan" size="small" />
                    </div> */}
            </MeterGroup>
        </div>
    );
}

Accessibility#

Screen Reader#

MeterGroup component uses meter role in addition to the aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using aria-labelledby prop.

Keyboard Support#

Component does not include any interactive elements.