shadimage
mksingh
componentjsonforms-anyof-string-or-enum-controlsource: ok · hit

Jsonforms Anyof String Or Enum Control

JSONForms combobox renderer for anyOf schemas that combine enum values with a plain string type. Renders a text input with a datalist dropdown — user can pick a suggestion or type freely.

npx shadcn add "https://mksingh.dev/r/jsonforms-anyof-string-or-enum-control.json"
free

Interaction

dropdown

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
@jsonforms/core@jsonforms/react

Registry dependencies

https://mksingh.dev/r/typography.jsoninput

Files1 · source cached 10/8/2026, 7:45:00 PM

registry/forms/renderers/anyof-string-or-enum-control.tsx
import { useState } from 'react';

import { ControlProps, JsonSchema, rankWith, UISchemaElement } from '@jsonforms/core';
import { withJsonFormsControlProps } from '@jsonforms/react';

import Typography from '~/components/ui/typography';
import { Input } from '~/components/ui/input';
import { Label } from '~/components/ui/label';
import { shouldShowError } from '~/components/forms/utils';

const hasEnumAndText = (schema: JsonSchema): boolean => {
    if (!schema.anyOf) return false;
    const hasEnum = schema.anyOf.some((s: JsonSchema) => s.enum !== undefined);
    const hasText = schema.anyOf.some((s: JsonSchema) => s.type === 'string' && s.enum === undefined);
    return hasEnum && hasText;
};

const AnyOfStringOrEnumControlRenderer = (props: ControlProps) => {
    const { label, data, handleChange, path, visible, enabled, schema, id, errors, config } = props;
    const [touched, setTouched] = useState(false);

    if (!visible) return null;

    const enumOptions = schema.anyOf
        ?.filter((s: JsonSchema) => s.enum !== undefined)
        .flatMap((s: JsonSchema) => s.enum as string[]) ?? [];

    const listId = `${id}-list`;

    return (
        <div className="flex flex-col gap-1 py-2">
            {label && <Label className="text-xs font-medium text-foreground">{label}</Label>}
            <Input
                list={listId}
                value={data ?? ''}
                onChange={e => handleChange(path, e.target.value)}
                onBlur={() => setTouched(true)}
                disabled={!enabled}
            />
            <datalist id={listId}>
                {enumOptions.map(opt => (
                    <option key={opt} value={opt} />
                ))}
            </datalist>
            {shouldShowError(config, touched) && errors && <Typography variant="error">{errors.split("\n")[0]}</Typography>}
        </div>
    );
};

export const anyOfStringOrEnumControlTester = rankWith(
    5,
    (_uischema: UISchemaElement, schema: JsonSchema) => {
        if (!schema) return false;
        return hasEnumAndText(schema);
    }
);
export default withJsonFormsControlProps(AnyOfStringOrEnumControlRenderer);

More from mksingh

Browse all components in this library →