Skip to content
Brok UI

Loading…

No results

Product Ingredients

Open source

Ingredient and spec breakdowns — icon-tile ingredient cards with a full-list accordion and trust claims.

Preview

resources/views/blocks/product-ingredients-grid.blade.php Blade
@props([
    'heading' => 'What\'s inside',
    'subheading' => 'Clean ingredients, nothing hidden.',
    'ingredients' => null,
    'fullList' => null,
    'claims' => null,
])

@php
    $ingredients ??= [
        [
            'name' => 'Hyaluronic Acid',
            'benefit' => 'Draws in moisture for plumper, dewy-looking skin.',
            'amount' => '2%',
            'icon' => 'M12 3c4 4 6 7 6 10a6 6 0 0 1-12 0c0-3 2-6 6-10Z',
        ],
        [
            'name' => 'Vitamin C',
            'benefit' => 'Brightens tone and defends against daily stressors.',
            'amount' => '15%',
            'icon' => 'M12 3v2 M12 19v2 M5 12H3 M21 12h-2 M6 6l1.5 1.5 M16.5 16.5 18 18 M6 18l1.5-1.5 M16.5 7.5 18 6 M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z',
        ],
        [
            'name' => 'Niacinamide',
            'benefit' => 'Refines pores and evens out the appearance of skin.',
            'amount' => '500mg',
            'icon' => 'M12 3a9 9 0 1 0 9 9 7 7 0 0 1-9-9Z',
        ],
        [
            'name' => 'Squalane',
            'benefit' => 'Lightweight plant oil that softens and seals in moisture.',
            'amount' => '5%',
            'icon' => 'M3 12c3-4 6-4 9 0s6 4 9 0 M3 17c3-4 6-4 9 0s6 4 9 0',
        ],
        [
            'name' => 'Green Tea Extract',
            'benefit' => 'Antioxidant-rich botanical that calms and soothes.',
            'amount' => '3%',
            'icon' => 'M4 20c0-7 5-13 16-15-2 11-8 15-13 15 M9 17c1-4 3-6 6-8',
        ],
        [
            'name' => 'Ceramides',
            'benefit' => 'Rebuilds the moisture barrier for resilient skin.',
            'amount' => '250mg',
            'icon' => 'M12 3 21 8v8l-9 5-9-5V8l9-5Z M12 3v18 M3 8l9 5 9-5',
        ],
    ];

    $fullList ??= [
        'Aqua (Water)',
        'Glycerin',
        'Sodium Hyaluronate',
        'Ascorbic Acid (Vitamin C)',
        'Niacinamide',
        'Squalane',
        'Camellia Sinensis (Green Tea) Leaf Extract',
        'Ceramide NP',
        'Tocopherol (Vitamin E)',
        'Panthenol (Pro-Vitamin B5)',
        'Citric Acid',
        'Sodium Benzoate',
    ];

    $claims ??= [
        'Vegan',
        'Cruelty-free',
        'No parabens',
        'Fragrance-free',
        'Dermatologist-tested',
    ];
@endphp

<x-ui.section
    data-slot="product-ingredients-01"
    space="xl" {{ $attributes }}
>
    <x-ui.container gutter="sm">
        <x-ui.section-heading align="center" :title="$heading" :subtitle="$subheading" />

        <ul role="list" class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
            @foreach ($ingredients as $ingredient)
                <li>
                    <x-ui.card class="h-full p-6">
                        <div class="flex items-start justify-between gap-4">
                            <span class="flex size-12 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
                                <svg
                                    class="size-6"
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="1.75"
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    aria-hidden="true"
                                >
                                    <path d="{{ $ingredient['icon'] }}" />
                                </svg>
                            </span>

                            <x-ui.badge variant="outline" class="font-mono">
                                {{ __($ingredient['amount']) }}
                            </x-ui.badge>
                        </div>

                        <h3 class="mt-4 text-sm font-semibold tracking-tight text-foreground">
                            {{ __($ingredient['name']) }}
                        </h3>
                        <p class="mt-2 text-pretty text-sm text-muted-foreground">
                            {{ __($ingredient['benefit']) }}
                        </p>
                    </x-ui.card>
                </li>
            @endforeach
        </ul>

        <div class="mx-auto mt-12 max-w-2xl">
            <x-ui.accordion>
                <x-ui.accordion.item value="full-ingredient-list">
                    <x-ui.accordion.trigger>{{ __('Full ingredient list') }}</x-ui.accordion.trigger>
                    <x-ui.accordion.content>
                        <p class="text-sm text-muted-foreground">
                            {{ __('Complete INCI breakdown, in descending order of concentration.') }}
                        </p>
                        <ul role="list" class="mt-4 flex flex-wrap gap-x-2 gap-y-2 text-sm text-foreground">
                            @foreach ($fullList as $i => $entry)
                                <li class="inline-flex items-center">
                                    {{ __($entry) }}@if (! $loop->last)<span class="text-muted-foreground" aria-hidden="true">,</span>@endif
                                </li>
                            @endforeach
                        </ul>
                    </x-ui.accordion.content>
                </x-ui.accordion.item>
            </x-ui.accordion>

            <x-ui.separator class="my-6" />

            <ul role="list" class="flex flex-wrap items-center justify-center gap-2">
                @foreach ($claims as $claim)
                    <li>
                        <x-ui.badge variant="secondary">{{ __($claim) }}</x-ui.badge>
                    </li>
                @endforeach
            </ul>
        </div>
    </x-ui.container>
</x-ui.section>

Installation

terminal
php artisan ui:add blocks/product-ingredients-grid

Registry contract

Install confidence

php artisan ui:add blocks/product-ingredients-grid writes only the generated targets below. The CLI validates each file hash before writing and prompts before replacing local changes unless --force is used.

Version
1.0.5
License
open
Stability
stable
Contract
v1
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/blocks/product-ingredients-grid.blade.php

Registry dependencies

accordion badge card container section section-heading separator

Package dependencies

composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.

product-ingredients-grid.md
# Brok UI block: Product Ingredients (`product-ingredients-grid`)

A "What's inside" ingredients and specs breakdown for a product page: a centered heading and reassurance subheading, a responsive grid of ingredient cards each with a tokened icon tile, the ingredient name, a one-line benefit, and an amount/percentage badge. Below the grid an accordion reveals the full INCI / nutrition-style ingredient list, followed by a centered row of trust badges (vegan, cruelty-free, no parabens).

Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.

## Install

```bash
php artisan ui:add blocks/product-ingredients-grid
```

## Render it

```blade
<x-blocks.product-ingredients-grid />
```

## Props

- `heading` (string, default `What\'s inside`) — Section heading.
- `subheading` (string, default `Clean ingredients, nothing hidden.`) — Supporting reassurance copy under the heading.
- `ingredients` (mixed|null, default `null`) — Array of {name, benefit, amount, icon} ingredient card entries.
- `full-list` (mixed|null, default `null`) — Array of full INCI/nutrition-style ingredient list line strings shown inside the accordion.
- `claims` (mixed|null, default `null`) — Array of trust badge label strings (e.g. vegan, cruelty-free).

## Use when

- Building a "What's inside" ingredients/specs section for a product page: a centred heading, a grid of ingredient cards (icon, name, benefit line, amount badge), and a row of trust badges (vegan, cruelty-free, no parabens).
- Wanting the full INCI/nutrition-style ingredient list tucked behind a collapsible accordion rather than always shown.

## Avoid when

- Needing a specifications table for technical product attributes rather than an ingredients grid; use product-overview-tabs's specs table instead.

## Rules

- Render the installed block with `<x-blocks.product-ingredients-grid />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.

## Links

- Docs: https://brokui.dev/blocks/product-ingredients-grid
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/product-ingredients-grid.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

Guidance

Use when

  • Building a "What's inside" ingredients/specs section for a product page: a centred heading, a grid of ingredient cards (icon, name, benefit line, amount badge), and a row of trust badges (vegan, cruelty-free, no parabens).
  • Wanting the full INCI/nutrition-style ingredient list tucked behind a collapsible accordion rather than always shown.

Avoid when

  • Needing a specifications table for technical product attributes rather than an ingredients grid; use product-overview-tabs's specs table instead.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.
Anatomy
heading subheading ingredient grid ingredient card icon tile amount badge full list accordion trust badges

Usage

Render the block as a component, passing data where useful:

resources/views/welcome.blade.php Blade
<x-blocks.product-ingredients-grid />

Built from primitives

Composes <brok:*> Semantic tokens Re-themeable RTL-ready

This block composes installed <brok:*> primitives and semantic design tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by editing CSS variables; flip the preview to RTL to confirm it mirrors.

Source

The exact, editable file ui:add writes into your app. The preview above renders this same source — there are no preview-only blocks.

resources/views/blocks/product-ingredients-grid.blade.php Blade
@props([
    'heading' => 'What\'s inside',
    'subheading' => 'Clean ingredients, nothing hidden.',
    'ingredients' => null,
    'fullList' => null,
    'claims' => null,
])

@php
    $ingredients ??= [
        [
            'name' => 'Hyaluronic Acid',
            'benefit' => 'Draws in moisture for plumper, dewy-looking skin.',
            'amount' => '2%',
            'icon' => 'M12 3c4 4 6 7 6 10a6 6 0 0 1-12 0c0-3 2-6 6-10Z',
        ],
        [
            'name' => 'Vitamin C',
            'benefit' => 'Brightens tone and defends against daily stressors.',
            'amount' => '15%',
            'icon' => 'M12 3v2 M12 19v2 M5 12H3 M21 12h-2 M6 6l1.5 1.5 M16.5 16.5 18 18 M6 18l1.5-1.5 M16.5 7.5 18 6 M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z',
        ],
        [
            'name' => 'Niacinamide',
            'benefit' => 'Refines pores and evens out the appearance of skin.',
            'amount' => '500mg',
            'icon' => 'M12 3a9 9 0 1 0 9 9 7 7 0 0 1-9-9Z',
        ],
        [
            'name' => 'Squalane',
            'benefit' => 'Lightweight plant oil that softens and seals in moisture.',
            'amount' => '5%',
            'icon' => 'M3 12c3-4 6-4 9 0s6 4 9 0 M3 17c3-4 6-4 9 0s6 4 9 0',
        ],
        [
            'name' => 'Green Tea Extract',
            'benefit' => 'Antioxidant-rich botanical that calms and soothes.',
            'amount' => '3%',
            'icon' => 'M4 20c0-7 5-13 16-15-2 11-8 15-13 15 M9 17c1-4 3-6 6-8',
        ],
        [
            'name' => 'Ceramides',
            'benefit' => 'Rebuilds the moisture barrier for resilient skin.',
            'amount' => '250mg',
            'icon' => 'M12 3 21 8v8l-9 5-9-5V8l9-5Z M12 3v18 M3 8l9 5 9-5',
        ],
    ];

    $fullList ??= [
        'Aqua (Water)',
        'Glycerin',
        'Sodium Hyaluronate',
        'Ascorbic Acid (Vitamin C)',
        'Niacinamide',
        'Squalane',
        'Camellia Sinensis (Green Tea) Leaf Extract',
        'Ceramide NP',
        'Tocopherol (Vitamin E)',
        'Panthenol (Pro-Vitamin B5)',
        'Citric Acid',
        'Sodium Benzoate',
    ];

    $claims ??= [
        'Vegan',
        'Cruelty-free',
        'No parabens',
        'Fragrance-free',
        'Dermatologist-tested',
    ];
@endphp

<x-ui.section
    data-slot="product-ingredients-01"
    space="xl" {{ $attributes }}
>
    <x-ui.container gutter="sm">
        <x-ui.section-heading align="center" :title="$heading" :subtitle="$subheading" />

        <ul role="list" class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
            @foreach ($ingredients as $ingredient)
                <li>
                    <x-ui.card class="h-full p-6">
                        <div class="flex items-start justify-between gap-4">
                            <span class="flex size-12 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
                                <svg
                                    class="size-6"
                                    viewBox="0 0 24 24"
                                    fill="none"
                                    stroke="currentColor"
                                    stroke-width="1.75"
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    aria-hidden="true"
                                >
                                    <path d="{{ $ingredient['icon'] }}" />
                                </svg>
                            </span>

                            <x-ui.badge variant="outline" class="font-mono">
                                {{ __($ingredient['amount']) }}
                            </x-ui.badge>
                        </div>

                        <h3 class="mt-4 text-sm font-semibold tracking-tight text-foreground">
                            {{ __($ingredient['name']) }}
                        </h3>
                        <p class="mt-2 text-pretty text-sm text-muted-foreground">
                            {{ __($ingredient['benefit']) }}
                        </p>
                    </x-ui.card>
                </li>
            @endforeach
        </ul>

        <div class="mx-auto mt-12 max-w-2xl">
            <x-ui.accordion>
                <x-ui.accordion.item value="full-ingredient-list">
                    <x-ui.accordion.trigger>{{ __('Full ingredient list') }}</x-ui.accordion.trigger>
                    <x-ui.accordion.content>
                        <p class="text-sm text-muted-foreground">
                            {{ __('Complete INCI breakdown, in descending order of concentration.') }}
                        </p>
                        <ul role="list" class="mt-4 flex flex-wrap gap-x-2 gap-y-2 text-sm text-foreground">
                            @foreach ($fullList as $i => $entry)
                                <li class="inline-flex items-center">
                                    {{ __($entry) }}@if (! $loop->last)<span class="text-muted-foreground" aria-hidden="true">,</span>@endif
                                </li>
                            @endforeach
                        </ul>
                    </x-ui.accordion.content>
                </x-ui.accordion.item>
            </x-ui.accordion>

            <x-ui.separator class="my-6" />

            <ul role="list" class="flex flex-wrap items-center justify-center gap-2">
                @foreach ($claims as $claim)
                    <li>
                        <x-ui.badge variant="secondary">{{ __($claim) }}</x-ui.badge>
                    </li>
                @endforeach
            </ul>
        </div>
    </x-ui.container>
</x-ui.section>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.0.5
Status
Stable
License
open
Deprecation
Not deprecated
Contract
v1
Foundation
≥ 1.0.0