Hydra AI

V 0.1.0 Coming Soon

These are draft docs for the upcoming 0.1.0 release. Read more about the upcoming release here. Have a question about anything in the docs? Send us a message.

Generative UX

Building dynamic interfaces with Hydra AI components.

Hydra AI enables you to create dynamic interfaces by orchestrating your React components. This guide will show you how to build components that work seamlessly with Hydra.

We'll cover two main approaches:

  • Display only components
  • Interactive components

Why make components interactive?

Let's say the user updates a component text value, and then ask your AI assistant can you edit the text. Hydra will use the same state of the component in the follow up message as context!

Our react hooks give yous out of the box:

  • Persistence
  • Type safety
  • Inclusion in subsequent messages

With no extra work on your part!

Simple Display Components

This is the simplest form of component. It takes in props and displays data.

Simple Data Display
const DataDisplay = ({ data }) => (
  <table>
    <thead>
      <tr>
        {Object.keys(data[0]).map((key) => (
          <th key={key}>{key}</th>
        ))}
      </tr>
    </thead>
    <tbody>
      {data.map((row, i) => (
        <tr key={i}>
          {Object.values(row).map((value, j) => (
            <td key={j}>{value}</td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
);
 
const DataDisplayDefinition = {
  component: DataDisplay, // [!code focus]
  propsSchema: z.object({
    data: z.array(z.record(z.string(), z.unknown())),
  }),
  description: "Display data in a table format",
};

Interactive Components

This is a little more complex. It takes in props and displays data. It also has a state that can be updated.

But we provide you with hooks to manage the state and validation that make it easy to create interactive components, with persistence, validation, and inclusion in subsequent messages.

Interactive Data Table
const InteractiveTable = ({ data }) => {
  const { value, setValue } = useHydraState();
  const filters = value?.filters ?? {};
 
  const handleFilter = (column, value) => {
    setValue({
      ...value,
      filters: { ...filters, [column]: value },
    });
  };
 
  const columns = Object.keys(data[0]);
 
  return (
    <>
      <div>
        {columns.map((col) => (
          <input
            key={col}
            placeholder={col}
            onChange={(e) => handleFilter(col, e.target.value)}
            value={filters[col] || ""}
          />
        ))}
      </div>
      <table>
        <thead>
          <tr>
            {columns.map((col) => (
              <th key={col}>{col}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {data.map((row, i) => (
            <tr key={i}>
              {columns.map((col) => (
                <td key={col}>{row[col]}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
};
 
const InteractiveTableDefinition = {
  component: InteractiveTable,
  propsSchema: z.object({
    data: z.array(z.record(z.string(), z.unknown())),
  }),
  description: "Interactive table with filtering",
};

Need another example?

Here is a form component that has a state that can be updated.

What's happening here?

  • We're using the useHydraState hook to manage the state of the form.
  • We're using the HydraMessageContext to keep track of the form data in the chat history.
Simple Form
const Form = ({ fields }) => {
  const { value, setValue } = useHydraState();
  const formData = value?.data ?? {};
 
  const handleSubmit = (e) => {
    e.preventDefault();
    setValue({ ...value, submitted: true });
  };
 
  return (
    <form onSubmit={handleSubmit}>
      {fields.map(({ name, type }) => (
        <div key={name}>
          <label>{name}</label>
          <input
            type={type}
            value={formData[name] || ""}
            onChange={(e) =>
              setValue({
                ...value,
                data: { ...formData, [name]: e.target.value },
              })
            }
          />
        </div>
      ))}
      <button type="submit">Submit</button>
    </form>
  );
};
 
const FormDefinition = {
  component: Form,
  propsSchema: z.object({
    fields: z.array(
      z.object({
        name: z.string(),
        type: z.string(),
      }),
    ),
  }),
  description: "Interactive form with state management",
};

Looking for streaming?

On this page