Do I need a macro to do this, or can I go away with something else?

Actually I would avoid using here __using__ as it is not necessary. I would something like this:

defmodule Attributes do
  defmacro generic_attributes() do
    quote do
      attr :class, :string, default: ""
      attr :id, :string, default: nil
      attr :rest, :global 
    end
  end
end

And using it inside of components by:

require Attributes

Attributes.generic_attributes()

The advantages are:

  1. Much more readability, as you can document the macro and have a clear understanding where you use it, opposed to use;
  2. Macro defined in this way can only inject code, to avoid people coming later and adding their “smart” ideas.