Field Style
This module allows users to apply advanced, responsive CSS styling to fields directly from the content editing form without custom code. Styles are saved with the content and rendered as scoped CSS on the front end, offering extensive options for visual customization across different screen sizes and states.
Field Style is a Drupal module that lets site builders and content editors apply advanced, responsive CSS styling to any field output — directly from the content edit form, with no custom code required. Styles are stored as JSON inside the field value, travel with content through exports and migrations, and are rendered as scoped CSS on the front end.
Compatible with Drupal 9.4, 10, 11, and 12.
Features at a glance
- 70+ CSS properties configurable per breakpoint and per pseudo-state (hover, active, focus, visited)
- Unlimited responsive breakpoints with optional icons, configurable in the admin UI or via hooks
- Container queries (
@container) support per formatter instance, with optional container name - Per-field breakpoint overrides — replace the global breakpoint set for a specific field
- Global styles — named reusable style blueprints provided via hooks or the admin UI
- Style presets — save, load, export, and import named snapshots as JSON files
- Site-wide color palette with clickable swatch picker in every color field
- 50-step undo/redo history with Ctrl+Z / Ctrl+Y keyboard shortcuts
- Live CSS preview panel with one-click Copy to clipboard
- Property search filter with real-time results
- Properties organized into collapsible accordion groups (Typography, Color, Spacing, Background, Border, Position, Effects, Animation)
- Background images via file upload or Drupal Media Library, with image style support
- Google Fonts integration — searchable catalogue, auto-injects the required link tag
- Custom font upload (TTF, EOT, WOFF, WOFF2) with automatic @font-face generation
- CSS aggregation — styles written to
public://field_style/css/and served as static files - Stale CSS file cleanup via cron with a configurable max-age setting
- Twig helper functions for headless and custom-template use cases
- Token support in CSS selectors — e.g.
.node-[node:nid] [state] - Multiple field_style fields on the same page each inject their own scoped CSS without collision
- CSP-safe — inline style tags carry a nonce when one is provided
- CSRF token protection on all AJAX endpoints
- Built with Vue 3 + Webpack 5 — ~410 KB bundle
- Ten developer hooks for breakpoints, fonts, image styles, global styles, and property transforms
Supported CSS properties
Typography: fontFamily, fontSize, fontWeight, fontStyle, textAlign, textAlignLast, textDecoration, textIndent, textTransform, letterSpacing, lineHeight, whiteSpace, wordBreak, wordSpacing, wordWrap
Color: color, fill, backgroundColor
Spacing: margin, marginTop, marginRight, marginBottom, marginLeft, padding, paddingTop, paddingRight, paddingBottom, paddingLeft
Size and Layout: width, height, maxWidth, minWidth, maxHeight, minHeight, display, flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, order, float, overflow, overflowX, overflowY
Background: background, backgroundImage, backgroundRepeat, backgroundRepeatX, backgroundRepeatY, backgroundPosition, backgroundPositionX, backgroundPositionY, backgroundSize, backgroundAttachment, backgroundClip, backgroundOrigin
Border: border, borderStyle, borderWidth, borderRadius, borderColor, borderTop, borderRight, borderBottom, borderLeft, and individual color/width/style per side
Position: position, top, right, bottom, left, zIndex, verticalAlign
Effects: boxShadow, boxSizing, textShadow, backfaceVisibility, cursor, visibility
Animation: transition, transitionTimingFunction, animation, animationDelay, animationDirection, animationFillMode, animationIterationCount, animationName, animationPlayState, animationTimingFunction
Requirements and installation
Requires Drupal core modules Field, Node, and Paragraphs. Optional integrations:
- Media — required for the Media Library background image picker
- Token — required for token substitution in CSS selectors
- Image — required for image style support in background images
- Place the module folder inside
modules/custom/or install via Composer. - Enable the module:
drush en field_style - Add the Field Style field to any content type, paragraph, or other fieldable entity via the Drupal field UI.
- Configure the display formatter to set the CSS selector and enable the features you need.
Editor UI
The in-form editor is a Vue 3 single-page application embedded inside the Drupal edit form. It keeps a hidden textarea holding the JSON value in sync on every change. The toolbar provides:
- Undo and Redo buttons (50-step history, Ctrl+Z / Ctrl+Y)
- Save preset — prompts for a name and stores the current styles
- Export presets — downloads all saved presets as a JSON file
- Import presets — reads a JSON file and saves each preset to the server
- Load preset dropdown — applies any saved preset to the current field (hidden when no presets exist)
- CSS preview toggle — opens a live preview panel with the generated CSS and a Copy button
Inside each breakpoint tab, quick-action buttons let editors Copy, Paste, Apply to all breakpoints, or Reset styles with a single click. A second tab row shows the enabled pseudo-states. A real-time search input filters across all properties, and each group (Typography, Color, Spacing, etc.) can be collapsed independently. Tab contents are only rendered when a tab is first activated, keeping initial page load fast.
Responsive breakpoints
Breakpoints are configured at Admin › Configuration › Field Style › Breakpoints. Each breakpoint has a machine name, a media query string, and an optional icon. Breakpoints can also be injected programmatically via hook_field_style_break_points(). The formatter additionally supports per-field breakpoint overrides — a textarea with one name|media_query entry per line — that completely replaces the global set for that specific field.
Container queries
When "Emit @container queries" is enabled on the display formatter, every breakpoint wrapper switches from @media to @container. The field wrapper automatically receives container-type: inline-size (and container-name when a name is configured) in its style attribute. This makes field styles respond to the width of a parent element rather than the viewport — ideal for reusable paragraph or block components placed in sidebars, modals, or any variable-width container.
Background images and Media Library
The backgroundImage property offers two sources accessible through tabs in the editor:
- File upload — drag-and-drop or click-to-browse. The uploaded file is stored as a managed Drupal file and its URL is refreshed automatically on load.
- Media Library — search interface backed by the module's media list endpoint, filtered by media type.
Both sources support selecting a Drupal image style (thumbnail, large, custom, etc.) applied at render time.
Global styles
Global styles are named, reusable style blueprints provided by modules or themes via hook_field_style_global_style() or configured at Admin › Configuration › Field Style › Global Styles. When the globalStyle property is enabled on a widget, editors see a dropdown listing all available global styles. Selecting one applies its full breakpoint/state/property tree as a base, and per-field overrides are merged on top at render time.
Style presets
Presets are editor-created snapshots of a complete field style value, stored in Drupal simple config and accessible across all entities and content types that have a Field Style field.
- Style a field the way you want.
- Click Save preset in the toolbar and enter a name.
- On any other field, use the Load preset dropdown to apply the saved styles in one click.
Use Export presets to download all presets as a JSON file. Use Import presets to upload a JSON file and merge those presets into the site — useful for moving styles between environments or sharing design libraries across projects.
Preset REST endpoints (all protected by CSRF token):
- GET
/field-style/preset/list— list all saved presets - GET
/field-style/preset/get/{id}— get full data for one preset - POST
/field-style/preset/save— create or overwrite a preset - POST
/field-style/preset/delete/{id}— delete a preset
Color palette and swatch picker
A site-wide color palette is configured at Admin › Configuration › Field Style › Settings (one CSS value per line — hex, RGB, named color, or CSS custom property such as var(--brand-primary)). Whenever an editor opens a color or backgroundColor property, the palette swatches appear as clickable tiles below the color picker. Clicking a swatch sets the value instantly.
CSS output and aggregation
By default, generated CSS is written to public://field_style/css/{sha256}.css and linked via <link rel="stylesheet">. This avoids inline style tags, enables browser caching for repeated styles, and is Content-Security-Policy friendly. Stale CSS files older than the configured number of days are removed automatically by cron.
When aggregation is disabled or a file write fails, an inline <style> tag is injected. A CSP nonce is attached when one is available from the request attributes or from hook_field_style_csp_nonce().
Multiple field_style fields on the same page each produce CSS keyed by a combination of the field name and a hash of the CSS content, so there are no silent overwrites even in views or listing pages.
Twig helper functions
Two Twig functions are available in all templates for headless or custom-template use:
field_style_inline_css(value, selector, field_name, options)— returns a<style>…</style>HTML string, or an empty string if there are no styles.field_style_raw_css(value, selector, field_name, options)— returns the raw CSS string only, for embedding inside your own style block.
The value parameter accepts the raw JSON string stored in the field or an already-decoded array. The options parameter accepts use_container_queries, container_name, and breakpoints_override.
Token support in selectors
When the Token module is enabled, Drupal tokens in the formatter's CSS selector are resolved at render time with the rendered entity as context. For example, a selector of .node-[node:nid] [state] resolves to .node-42:hover { … } for node 42. The resolved selector is re-sanitized after token replacement.
Security
- All AJAX endpoints (image upload, media list, presets) require a CSRF token as the
?token=query parameter, validated by a dedicated access checker service. - User-supplied CSS selector overrides are run through a character allow-list filter before being persisted or emitted.
- Container names are stripped of all characters except letters, digits, hyphens, and underscores.
- The preset save endpoint rejects payloads larger than 256 KB.
- Inline style tags carry a CSP nonce when one is available, so sites using
style-src 'nonce-…'do not need to allow'unsafe-inline'. - The media library endpoint only returns items accessible to the current user.
Developer hooks
hook_field_style_global_style(&$vars)— provide named global style presetshook_field_style_break_points(&$values)— add or modify breakpointshook_field_style_google_fonts(&$values)— inject additional Google Font entrieshook_field_style_custom_font(&$values)— register custom font familieshook_field_style_global_image_style(&$vars)— provide additional image style optionshook_field_style_property_background_image(&$values)— transform background image valueshook_field_style_property(&$property, &$value, …)— intercept any property at render timehook_field_style_property_PROPERTY(&$value, …)— target a specific property by namehook_field_style_global_pre_render_style(&$style, …)— alter the full style tree before CSS generationhook_field_style_csp_nonce()— return a CSP nonce string for inline style tags
Full signatures and examples for each hook are in field_style.api.php.
Administration pages
/admin/config/field-style— main settings: CSS aggregation, max-age, color palette/admin/config/field-style/settings/break-points— manage responsive breakpoints/admin/config/field-style/settings/google-fonts— Google Fonts API key and font selection/admin/config/field-style/settings/custom-fonts— upload and manage custom font files/admin/config/field-style/settings/global-styles— manage globally reusable styles