Estructura HTML
Un formulario básico se estructura de la siguiente manera:
<div class="formulaire_spip formulaire_editer formulaire_editer_nomformulaire formulaire_editer_nomformulaire-id">
<a id="nomformulaire" name="nomformulaire"></a>
<form action="#" method="post">
  <fieldset>
    <legend>Una Leyenda</legend>
    <p class="explication">Explicación del formulario</p>
    <div class="editer-groupe">
      <div class="editer editer_nomlabel obligatoire erreur">
        <label for="nomlabel">Correo</label>
        <em class="aide">#AIDER{arttitre}</em>
        <p class="explication"> Explicación de la etiqueta</p>
        <span class="erreur_message">Mensaje de error</span>
        <input type="type" class="type" name="nomlabel" id="nomlabel" value="" />
      </div>
    </div>
  </fieldset>
</form>
</div>
La etiqueta <div> en el recuadro de arriba tiene la clase formulaire_spip genérica . Los formularios de edición en el área privada también tienen la clase formulaire_editer que indica que estamos tratando con un formulario de edición de base de datos.
Cada campo de entrada está encapsulado en un elemento de clase .editer, que debe agruparse en un elemento de clase .editer-groupe. Hasta SPIP 3.0, estas clases se llevaban a cabo mediante las etiquetas html li y ul. A partir de SPIP 3.1, tomamos como convención el uso de  div para reducir la síntesis de voz y mejorar la accesibilidad de los formularios.
El primer conjunto de campos es opcional, también podemos escribir, sin el conjunto de campos y sin los párrafos opcionales:
<div class="formulaire_spip formulaire_editer formulaire_editer_nomformulaire formulaire_editer_nomformulaire-id">
<a id="nomformulaire" name="nombre del formulario"></a>
<form action="#" method="post">
  <div class="editer-groupe">
    <div class="editer editer_nomlabel obligatoire">
      <label for="nomlabel">Correo</label>
      <input type="type" class="type" name="nomlabel" id="nomlabel" value="" />
    </div>
  </div>
</form>
</div>
Las clases especiales
-  « explication »:  para indicar un mensaje de explicación (que se relaciona con todos los campos o con un paso). Ejemplo: 
<p class="explication">. -  « attention »: para mostrar un mensaje sobre un campo de edición crítico. Ejemplo: 
<em class="attention"><:texte_login_precaution:></em>. -  « obligatoire »: para indicar un campo obligatorio, que se aplicará al elemento de la lista principal.  Ejemplo: 
<div class="obligatoire">. -  « erreur »: para informar de un error, que se aplicará al elemento de la lista principal. Ejemplo: 
<div class="erreur">. Cada error tiene un mensaje explicativo, con la clase « erreur_message »:<span class="erreur_message">. 
Marco incluyente
Este formulario puede incluir opcionalmente un marco de edición de formulario y luego puede contener un encabezado de formulario:
<div class="cadre-formulaire-editer">
  <div class="entete-formulaire"></div>
  <div class="formulaire_editer formulaire_editer_site formulaire_editer_site-#ENV{id_site,nouveau}"></div>
</div>
Gestión de mensajes de éxito / error
Mensajes globales
Un formulario debe contener obligatoriamente dos párrafos que permitan mostrar los aciertos y errores generales que puedan presentarse durante el envío. Las variables de entornomessage_ok y message_erreur son respuestas enviadas por SPIP (formularios CVT).
<div class="formulaire_editer formulaire_editer_site formulaire_editer_site-#ENV{id_site,nouveau}">
  [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
  [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
</div>
Mensajes específicos
Cada campo de formulario, encapsulado en un li, puede recibir un mensaje de error específico. Está contenido en la tabla de entorno de ’errores’ y se puede obtener de la siguiente manera:
[(#ENV**{erreurs}|table_valeur{nombre_de_campo})]
Podemos asignar la clase ’error’ al li y mostrar un error específico, si existe, así:
<div class="editer editer_descriptif[ (#ENV**{erreurs}|table_valeur{descriptif}|oui)erreur]">
  <label for="descriptif"><:texte_descriptif_rapide:></label>
  [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{desctiptif})</span>]
  <textarea name='descriptif' id='descriptif' rows='2' cols='40'>[(#ENV**{descriptif})]</textarea>
</div>
Particularidades para los estilos css
Campos de entrada
Cada <input /> diferente de hidden debe tener una clase idéntica a su tipo (para superar una deficiencia del navegador Internet Explorer):
<input type="text" class="text" name="titre" id="titre" value="[(#ENV**{titre})]" />
Botones de envío
Los botones de envío se incluyen en un cuadro .boutons (que puede acomodar varios botones):
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
casillas radio/checkbox
En el caso de un botón de radio o casilla de verificación(checkbox), no podemos usar la misma estructura, por ejemplo, para tener el botón antes de la etiqueta, o para tener la lista de radio en horizontal.
Cada entrada (radio + etiqueta) se puede enmarcar con un bloque .choix
<div class="editer editer_syndication">
  <div class="choix">
    <input type='radio' class="radio" name='syndication' value='non' id='syndication_non'[ (#ENV{syndication}|=={non}|?{'checked="checked"'})] />
    <label for='syndication_non'><:bouton_radio_non_syndication:></label>
  </div>
  <div class="choix">
    <input type='radio' class="radio" name='syndication' value='si' id='syndication_oui'[ (#ENV{syndication}|=={si}|?{'checked="checked"'})] />
    <label for='syndication_oui'><:bouton_radio_syndication:><em>#AIDER{rubsyn}</em></label>
  </div>
</div>
De forma predeterminada la lista es vertical. Para hacer la lista horizontal, todo lo que tiene que hacer es especificar que el campo en cuestión es de tipo en línea (inline):
.formulaire_editer .editer_syndication .choix {display:inline;}