npm package: @slhs/spark-combobox
Description: Spark UI Combobox component packaged up for SLHS
Author: SLHS Web Services
Latest version: 1.3.1

# @slhs/spark-combobox

The [`Combobox`](https://sparkui.vercel.app/?path=/docs/components-combobox--docs) component from
the [Spark UI design system](https://sparkui.vercel.app/) with a CSS file and Tailwind config
wrapper to override some of their styles.

[![npm Version](https://img.shields.io/npm/v/@slhs/spark-combobox.svg?style=for-the-badge)](https://www.npmjs.com/package/@slhs/spark-combobox)
[![Build Status](https://img.shields.io/badge/CI-GitHub%20Actions-success?logo=github&style=for-the-badge)](https://github.com/slhs/spark-combobox/actions?query=workflow%3Aci)

## Installation

```sh
npm install @slhs/spark-combobox
```

## Usage

This package assumes you're using Tailwind CSS and:

1.  Your main CSS file (e.g., `app.css`) looks something like this:

    ```css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    @layer base {
      :root {
        /* Primary */
        --color-brand-dark-blue: 0 44 119;
        /* Secondary blue hues */
        --color-brand-light-blue: 104 172 229;
        --color-brand-sky-blue: 37 194 230;
        --color-brand-brilliant-blue: 0 146 208;
        --color-brand-lapis-blue: 31 108 180;
        --color-brand-steel-blue: 64 88 104;
        /* Accent colors */
        --color-brand-buttercup: 255 222 117;
        --color-brand-canary: 235 186 30;
        --color-brand-tangerine: 246 142 30;
        --color-brand-kelly-green: 20 161 88;
        --color-brand-teal: 0 174 170;
        --color-brand-purple: 124 43 131;
        /* Neutral palette */
        --color-brand-concrete: 209 210 212;
        --color-brand-slate: 96 96 96;
        --color-brand-sand: 230 228 212;

        /* Abstract color names */
        --color-primary: var(--color-brand-dark-blue);
        --color-primary-hover: 51 66 142;
        --color-primary-active: 0 25 100;
        --color-secondary: var(--color-brand-slate);
        --color-secondary-hover: 105 105 105;
        --color-secondary-active: 89 89 89;
        --color-danger: 220 38 38;
        --color-danger-hover: 239 68 68;
        --color-danger-active: 201, 8, 8;
      }
    }

    /* Override input ring/border color from @tailwindcss/forms plugin with our primary color */
    input[type='text'],
    input[type='password'],
    input[type='email'],
    input[type='number'],
    input[type='url'],
    input[type='date'],
    input[type='datetime-local'],
    input[type='month'],
    input[type='week'],
    input[type='time'],
    input[type='search'],
    input[type='tel'],
    input[type='checkbox'],
    input[type='radio'],
    select,
    select[multiple],
    textarea {
      @apply ring-primary focus:border-primary;
    }
    ```

2.  Your Tailwind config file (e.g., `tailwind.config.ts`) looks something like this:

    ```ts
    import { withSparkCombobox } from '@slhs/spark-combobox/tw';

    /** @type {import('tailwindcss').Config} */
    const config = withSparkCombobox({
      content: ['./index.html', './src/**/*.tsx'],
      theme: {
        extend: {
          colors: {
            /* Literal color names */
            // Primary
            'brand-dark-blue': 'rgb(var(--color-brand-dark-blue) / <alpha-value>)',
            // Secondary blue hues
            'brand-light-blue': 'rgb(var(--color-brand-light-blue) / <alpha-value>)',
            'brand-sky-blue': 'rgb(var(--color-brand-sky-blue) / <alpha-value>)',
            'brand-brilliant-blue': 'rgb(var(--color-brand-brilliant-blue) / <alpha-value>)',
            'brand-lapis-blue': 'rgb(var(--color-brand-lapis-blue) / <alpha-value>)',
            'brand-steel-blue': 'rgb(var(--color-brand-steel-blue) / <alpha-value>)',
            // Accent colors
            'brand-buttercup': 'rgb(var(--color-brand-buttercup) / <alpha-value>)',
            'brand-canary': 'rgb(var(--color-brand-canary) / <alpha-value>)',
            'brand-tangerine': 'rgb(var(--color-brand-tangerine) / <alpha-value>)',
            'brand-kelly-green': 'rgb(var(--color-brand-kelly-green) / <alpha-value>)',
            'brand-teal': 'rgb(var(--color-brand-teal) / <alpha-value>)',
            'brand-purple': 'rgb(var(--color-brand-purple) / <alpha-value>)',
            // Neutral palette
            'brand-concrete': 'rgb(var(--color-brand-concrete) / <alpha-value>)',
            'brand-slate': 'rgb(var(--color-brand-slate) / <alpha-value>)',
            'brand-sand': 'rgb(var(--color-brand-sand) / <alpha-value>)',

            /* Abstract color names */
            primary: {
              DEFAULT: 'rgb(var(--color-primary) / <alpha-value>)',
              hover: 'rgb(var(--color-primary-hover) / <alpha-value>)',
              active: 'rgb(var(--color-primary-active) / <alpha-value>)',
            },
            secondary: {
              DEFAULT: 'rgb(var(--color-secondary) / <alpha-value>)',
              hover: 'rgb(var(--color-secondary-hover) / <alpha-value>)',
              active: 'rgb(var(--color-secondary-active) / <alpha-value>)',
            },
            danger: {
              DEFAULT: 'rgb(var(--color-danger) / <alpha-value>)',
              hover: 'rgb(var(--color-danger-hover) / <alpha-value>)',
              active: 'rgb(var(--color-danger-active) / <alpha-value>)',
            },
          },
        },
      },
    });

    export default config;
    ```

The override styles rely on this combined configuration for referencing certain values, e.g.
`var(--color-primary)` and `bg-brand-concrete/40`. If you don't have these in place, you'll need to
adjust the override styles accordingly. The `withSparkCombobox()` wrapper ensures all the default
Tailwind classes Spark UI uses are included and also generates a few additional Spark-specific
utility classes.

Once you've got the above in place, the next step is to copy the override styles from
[`spark-combobox.css`](./spark-combobox.css) into your project. Import the styles in whichever way
makes sense for your project (e.g., in a Remix v2 app, import the `spark-combobox.css` file to get a
URL and include that URL in your exported `links` function). Customize your local copy of this file
as needed.

Finally, import the component from this package like so:

```tsx
import { Combobox } from '@slhs/spark-combobox';
```

Refer to the
[Spark UI `Combobox` docs](https://sparkui.vercel.app/?path=/docs/components-combobox--docs) for
usage instructions.

<!-- prettier-ignore -->
> [!WARNING]
> At this time, the `Combobox` component does not server render well. You should wrap it with
> [`ClientOnly`](https://github.com/sergiodxa/remix-utils?tab=readme-ov-file#clientonly) to avoid
> hydration mismatches.