Advanced Components

Color Picker

A color panel with a saturation area, hue and alpha sliders, a hex field, palette swatches, and a screen eyedropper. Built to sit inside a popover, but it renders anywhere.

Example

A color picker in a popover, the way it is most often used.

Basic color picker
<div buiPopover>
<button matButton buiPopoverTrigger>
{{ color() || 'Pick a color' }}
</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<bui-color-picker [(value)]="color" />
</div>
</ng-template>
</div>

Usage

Unlike most Advanced Components, the color picker is a single component rather than a set of composable directives. Drop bui-color-picker anywhere and bind its value.

<!-- Two-way binding -->
<bui-color-picker [(value)]="color" />

<!-- One-way binding with your own handler -->
<bui-color-picker
[value]="color()"
(valueChange)="onColorChange($event)"
/>

value is a hex string. Everything the picker writes back is canonical lowercase hex: #3b82f6, or eight digits when alpha is enabled and the color is translucent. An empty string means no color and leaves the hex field showing its placeholder.

Input is forgiving. The hex field accepts a bare hex without the #, or any CSS color string such as rebeccapurple or rgb(59 130 246), and reformats it to hex on blur or Enter. Text that cannot be parsed restores the current color instead of clearing it.

bui-color-picker

The saturation area, hue slider, and alpha slider are pointer driven and work the same with a mouse, a pen, or touch. The pointer is captured on press, so a drag keeps tracking after it leaves the track and ends wherever it is released.

PropTypeDefaultDescription
valuemodel<string>'' Two-way binding for the selected color. Reads any CSS color, writes canonical lowercase hex. An empty string means no color.
alphabooleanfalse Shows the alpha slider and switches the output to eight-digit hex for translucent colors.
palettestring[][] Preset colors rendered as swatches under the sliders. The row is omitted when the array is empty.
recentColorsbooleantrue Shows the Recently used row. Set it to false to hide the row and stop the picker from recording colors.
classClassValue'' Classes merged onto the host element. Use it to constrain the width when the picker is rendered inline.

Alpha

Add the alpha attribute to enable transparency. A checkered alpha slider appears below the hue slider and the value becomes an eight-digit hex whenever the color is not fully opaque. Without it, alpha is pinned to 1 and any transparency in an incoming color is dropped.

Picker with alpha
#
#f59e0bcc
<!-- Opaque only, e.g. #f59e0b -->
<bui-color-picker [(value)]="color" />

<!-- With the alpha slider, e.g. #f59e0bcc -->
<bui-color-picker alpha [(value)]="color" />

Palette

Pass a list of hex colors to palette to offer presets such as brand colors, a chart scale, or whatever set your app works with. Picking a swatch sets the value and moves the sliders to it. The active swatch is outlined when it matches the current value.

Picker with a palette
#
Color palette
#3b82f6
<!-- Swatches from a component property -->
<bui-color-picker [palette]="palette" [(value)]="color" />

<!-- Or inline -->
<bui-color-picker
[palette]="['#ef4444', '#f59e0b', '#22c55e']"
[(value)]="color"
/>

Recently used

Below the palette the picker shows a Recently used row with the ten most recent colors. The list is held by the BuiRecentColors service and shared by every picker in the app, so a color chosen in one panel is one click away in the next. It is persisted to local storage, so it also survives a reload.

A color is remembered when the picker is destroyed, typically when the popover closes, and only when it differs from the color the picker opened with. Dragging across the saturation area therefore leaves a single entry for the color you landed on, not one for every intermediate step.

Set [recentColors]="false" to opt out. The row is not rendered and the picker records nothing, so the shared list is left untouched.

<!-- Without the recently used row -->
<bui-color-picker [recentColors]="false" [(value)]="color" />

Eyedropper

When the browser supports the EyeDropper API, the hex field gets a pipette button that lets the user sample any pixel on the screen. Support is currently limited to Chromium-based browsers. Elsewhere the button is simply not rendered, so there is nothing to feature-detect on your side.

Inline usage

The host is a full-width column, which is what makes it fit a popover panel without any extra styling. Rendered inline it would stretch to its container, so give it a width through the class input or wrap it in a sized card.

<!-- Inline: constrain the width yourself -->
<bui-color-picker class="w-64" [(value)]="color" />

<!-- In a card -->
<div class="w-72 rounded-xl border p-4">
<bui-color-picker [(value)]="color" />
</div>

<!-- In a popover: the panel already provides the width -->
<div buiPopoverContent>
<bui-color-picker [(value)]="color" />
</div>