{"id":256018,"date":"2017-06-26T04:21:18","date_gmt":"2017-06-26T11:21:18","guid":{"rendered":"http:\/\/css-tricks.com\/?p=256018"},"modified":"2017-06-29T18:32:40","modified_gmt":"2017-06-30T01:32:40","slug":"form-validation-part-1-constraint-validation-html","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/form-validation-part-1-constraint-validation-html\/","title":{"rendered":"Form Validation Part 1: Constraint Validation in HTML"},"content":{"rendered":"

Most JavaScript form validation libraries are large, and often require other libraries like jQuery. For example, MailChimp’s embeddable form includes a 140kb validation file (minified). It includes the entire jQuery library, a third-party form validation plugin, and some custom MailChimp code. In fact, that setup is what inspired this new series about modern form validation. What new tools do we have these days for form validation? What is possible? What is still needed?<\/p>\n

In this series, I’m going to show you two lightweight ways to validate forms on the front end. Both take advantage of newer web APIs. I’m also going to teach you how to push browser support for these APIs back to IE9 (which provides you with coverage for 99.6% of all web traffic worldwide).<\/p>\n

Finally, we’ll take a look at MailChimp’s sign-up form, and provide the same experience with 28\u00d7 less code.<\/p>\n

<\/p>\n

It’s worth mentioning that front-end form validation can be bypassed. You should always validate your code on the server, too.<\/strong><\/p>\n

Alright, let’s get started!<\/p>\n

\n

Article Series:<\/h4>\n
    \n
  1. Constraint Validation in HTML (You are here!)<\/li>\n
  2. The Constraint Validation API in JavaScript<\/a><\/li>\n
  3. A Validity State API Polyfill<\/a><\/li>\n
  4. Validating the MailChimp Subscribe Form<\/a><\/li>\n<\/ol>\n<\/div>\n

    The Incredibly Easy Way: Constraint Validation<\/h3>\n

    Through a combination of semantic input types (for example, <input type=\"email\"><\/code>) and validation attributes (such as required<\/code> and pattern<\/code>), browsers can natively validate form inputs and alert users when they’re doing it wrong.<\/p>\n

    Support for the various input types and attributes varies wildly from browser to browser<\/a>, but I’ll provide some tricks and workarounds to maximize browser compatibility.<\/p>\n

    Basic Text Validation<\/h4>\n

    Let’s say you have a text field that is required for a user to fill out before the form can be submitted. Add the required<\/code> attribute, and supporting browsers will both alert users who don’t fill it out and refuse to let them submit the form.<\/p>\n

    <input type=\"text\" required><\/code><\/pre>\n
    \"\"
    A required text input in Chrome.<\/figcaption><\/figure>\n

    Do you need the response to be a minimum or maximum number of characters? Use minlength<\/code> and maxlength<\/code> to enforce those rules. This example requires a value to be between 3 and 12 characters in length.<\/p>\n

    <input type=\"text\" minlength=\"3\" maxlength=\"12\"><\/code><\/pre>\n
    \"\"
    Error message for the wrong number of characters in Firefox.<\/figcaption><\/figure>\n

    The pattern<\/code> attribute let’s you run regex validations against input values. If you, for example, required passwords to contain at least 1 uppercase character, 1 lowercase character, and 1 number, the browser can validate that for you.<\/p>\n

    <input type=\"password\" pattern=\"^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s).*$\" required><\/code><\/pre>\n
    \"\"
    Wrong format error message in Safari.<\/figcaption><\/figure>\n

    If you provide a title<\/code> attribute with the pattern<\/code>, the title<\/code> value will be included with any error message if the pattern doesn’t match.<\/p>\n

    <input type=\"password\" pattern=\"^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s).*$\" title=\"Please include at least 1 uppercase character, 1 lowercase character, and 1 number.\" required><\/code><\/pre>\n
    \"\"
    Wrong format message in Opera, with title text explaining RegEx.<\/figcaption><\/figure>\n

    You can even combine it with minlength<\/code> and (as seems to be the case with banks, maxlength<\/code>) to enforce a minimum or maximum length.<\/p>\n

    <input type=\"password\" minlength=\"8\" pattern=\"^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s).*$\" title=\"Please include at least 1 uppercase character, 1 lowercase character, and 1 number.\" required><\/code><\/pre>\n

    See the Pen Form Validation: Basic Text<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    Validating Numbers<\/h4>\n

    The number<\/code> input type only accepts numbers. Browsers will either refuse to accept letters and other characters, or alert users if they use them. Browser support for input[type=\"number\"]<\/code> varies, but you can supply a pattern<\/code> as a fallback.<\/p>\n

    <input type=\"number\" pattern=\"[-+]?[0-9]\"><\/code><\/pre>\n

    By default, the number<\/code> input type allows only whole numbers. <\/p>\n

    You can allow floats (numbers with decimals) with the step<\/code> attribute. This tells the browser what numeric interval to accept. It can be any numeric value (example, 0.1<\/code> ), or any<\/code> if you want to allow any number.<\/p>\n

    You should also modify your pattern<\/code> to allow decimals.<\/p>\n

    <input type=\"number\" step=\"any\" pattern=\"[-+]?[0-9]*[.,]?[0-9]+\"><\/code><\/pre>\n

    If the numbers should be between a set of values, the browser can validate those with the min<\/code> and max<\/code> attributes. You should also modify your pattern<\/code> to match. For example, if a number has to be between 3 and 42, you would do this:<\/p>\n

    <input type=\"number\" min=\"3\" max=\"42\" pattern=\"[3-9]|[1-3][0-9]|4[0-2]\"><\/code><\/pre>\n

    See the Pen Form Validation: Numbers<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    Validating Email Addresses and URLs<\/h4>\n

    The email<\/code> input type will alert users if the supplied email address is invalid. Like with the number<\/code> input type, you should supply a pattern for browsers that don’t support this input type.<\/p>\n

    Email validation regex patterns are a hotly debated issue. I tested a ton of them specifically looking for ones that met RFC822 specs. The one used below, by Richard Willis<\/a>, was the best one I found.<\/p>\n

    <input type=\"email\" pattern=\"^([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d))*$\"><\/code><\/pre>\n

    One “gotcha” with the the email<\/code> input type is that it allows email addresses without a TLD (the “example.com” part of “email@example.com”). This is because RFC822<\/a>, the standard for email addresses, allows for localhost emails which don’t need one.<\/p>\n

    If you want to require a TLD (and you likely do), you can modify the pattern<\/code> to force a domain extension like so:<\/p>\n

    <input type=\"email\" title=\"The domain portion of the email address is invalid (the portion after the @).\" pattern=\"^([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d))*(\\.\\w{2,})+$\"><\/code><\/pre>\n

    Similarly, the url<\/code> input type will alert users if the supplied value is not a valid URL. Once again, you should supply a pattern for browsers that don’t support this input type. The one included below was adapted from a project by Diego Perini<\/a>, and is the most robust I’ve encountered.<\/p>\n

    <input type=\"url\" pattern=\"^(?:(?:https?|HTTPS?|ftp|FTP):\\\/\\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*)(?::\\d{2,})?(?:[\\\/?#]\\S*)?$\"><\/code><\/pre>\n

    Like the email<\/code> attribute, url<\/code> does not require a TLD. If you don’t want to allow for localhost URLs, you can update the pattern to check for a TLD, like this.<\/p>\n

    <input type=\"url\" title=\"The URL is a missing a TLD (for example, .com).\" pattern=\"^(?:(?:https?|HTTPS?|ftp|FTP):\\\/\\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-zA-Z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,})?(?:[\/?#]\\S*)?$\"><\/code><\/pre>\n

    See the Pen Form Validation: Email & URLs<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    Validating Dates<\/h4>\n

    There are a few really awesome input types that not only validate dates but also provide native date pickers. Unfortunately, Chrome, Edge, and Mobile Safari are the only browsers that implement it. (I’ve been waiting years<\/em> for Firefox to adopt this feature! Update:<\/strong> this feature should hopefully be coming to Firefox in the near future<\/a>, too.) Other browsers just display it as a text field.<\/p>\n

    As always, we can provide a pattern<\/code> to catch browsers that don’t support it.
    \nThe date<\/code> input type is for standard day\/month\/year dates.<\/p>\n

    <input type=\"date\" pattern=\"(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))\"><\/code><\/pre>\n

    In supporting browsers, the selected date is displayed like this: MM\/DD\/YYYY<\/code> (caveat:<\/strong> in the US. This can vary for users in other countries or who have modified their date settings). But the value<\/code> is actually in this format: YYYY-MM-DD<\/code>.<\/p>\n

    You should provide guidance to users of unsupported browsers about this format\u2014something like, “Please use the YYYY-MM-DD format.” However, you don’t want people visiting with Chrome or Mobile Safari to see this since that’s not the format they’ll see, which is confusing.<\/p>\n

    See the Pen Form Validation: Dates<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    A Simple Feature Test<\/h4>\n

    We can write a simple feature test to check for support, though. We’ll create an input[type=\"date\"]<\/code> element, add a value that’s not a valid date, and then see if the browser sanitizes it or not. You can then hide the descriptive text for browsers that support the date<\/code> input type.<\/p>\n

    <label for=\"date\">Date <span class=\"description-date\">YYYY-MM-DDD<\/span><\/label>\r\n<input type=\"date\" id=\"date\" pattern=\"(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))\">\r\n\r\n<script>\r\n  var isDateSupported = function () {\r\n      var input = document.createElement('input');\r\n      var value = 'a';\r\n      input.setAttribute('type', 'date');\r\n      input.setAttribute('value', value);\r\n      return (input.value !== value);\r\n  };\r\n\r\n  if (isDateSupported()) {\r\n      document.documentElement.className += ' supports-date';\r\n  }\r\n<\/scipt>\r\n\r\n<style>\r\n  .supports-date .description-date {\r\n      display: none;\r\n  }\r\n<\/style><\/code><\/pre>\n

    See the Pen Form Validation: Dates with a Feature Test<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    Other Date Types<\/h4>\n

    The time<\/code> input type let’s visitors select a time, while the month<\/code> input type let’s them choose from a month\/year picker. Once again, we’ll include a pattern for non-supporting browsers.<\/p>\n

    <input type=\"time\" pattern=\"(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9])\">\r\n<input type=\"month\" pattern=\"(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2]))\"><\/code><\/pre>\n

    The time<\/code> input displays time in 12-hour am\/pm format, but the value<\/code> is 24-hour military time. The month<\/code> input is displayed as May 2017<\/code> in supporting browsers, but the value is in YYYY-MM<\/code> format.<\/p>\n

    Just like with input[type=\"date\"]<\/code>, you should provide a pattern description that’s hidden in supporting browsers.<\/p>\n

    See the Pen Form Validation: Add `novalidate` programatically<\/a> by Chris Ferdinandi (@cferdinandi<\/a>) on CodePen<\/a>.<\/p>\n

    This seems super easy. What’s the catch?<\/h3>\n

    While the Constraint Validation API is easy and light-weight, it does have some drawbacks.<\/p>\n

    You can style fields that have errors on them with the :invalid<\/code> pseudo-selector, but you can’t style the error messages themselves.<\/p>\n

    Behavior is also inconsistent across browsers. Chrome doesn’t display any errors until you try to submit the form. Firefox displays a red border when the field loses focus, but only displays error messages on hover (whereas WebKit browsers keep the errors persistent).<\/p>\n

    User studies from Christian Holst<\/a> and Luke Wroblewski<\/a> (separately) found that displaying an error when the user leaves a field, and keeping that error persistent until the issue is fixed, provided the best and fastest user experience. Bonus CSS tip: style invalid selectors only when they aren’t currently being edited with :not(:focus):invalid { }<\/code>.<\/p>\n

    Unfortunately, none of the browsers behave exactly this way by default.<\/p>\n

    In the next article in this series, I’ll show you how to use the native Constraint Validation API to bolt-in our desired UX with some lightweight JavaScript. No third-party library required!<\/p>\n

    \n

    Article Series:<\/h4>\n
      \n
    1. Constraint Validation in HTML (You are here!)<\/li>\n
    2. The Constraint Validation API in JavaScript<\/a><\/li>\n
    3. A Validity State API Polyfill<\/a><\/li>\n
    4. Validating the MailChimp Subscribe Form<\/a><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"

      Most JavaScript form validation libraries are large, and often require other libraries like jQuery. For example, MailChimp’s embeddable form includes a 140kb validation file (minified). It includes the entire jQuery library, a third-party form validation plugin, and some custom MailChimp code. In fact, that setup is what inspired this new series about modern form validation. […]<\/p>\n","protected":false},"author":249049,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[1173,595,932],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":256250,"url":"https:\/\/css-tricks.com\/use-third-party-form-validation-library\/","url_meta":{"origin":256018,"position":0},"title":"Why Use a Third-Party Form Validation Library?","date":"July 3, 2017","format":false,"excerpt":"We've just wrapped up a great series of posts from Chris Ferdinandi on modern form validation. It starts here. These days, browsers have quite a few built-in tools for handling form validation including HTML attributes that can do quite a bit on their own, and a JavaScript API that can\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":336775,"url":"https:\/\/css-tricks.com\/creating-custom-form-controls-with-elementinternals\/","url_meta":{"origin":256018,"position":1},"title":"Creating Custom Form Controls with ElementInternals","date":"March 24, 2021","format":false,"excerpt":"Ever since the dawn of time, humanity has dreamed of having more control over form elements. OK, I might be overselling it a tiny bit, but creating or customizing form components has been a holy grail of front-end web development for years. One of the lesser-heralded, but most powerful features\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/custom-element-form.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":337536,"url":"https:\/\/css-tricks.com\/headless-form-submission-with-the-wordpress-rest-api\/","url_meta":{"origin":256018,"position":2},"title":"Headless Form Submission With the WordPress REST API","date":"April 9, 2021","format":false,"excerpt":"If you\u2019re building a WordPress site, you need a good reason not to choose a WordPress form plugin. They are convenient and offer plenty of customizations that would take a ton of effort to build from scratch. They render the HTML, validate the data, store the submissions, and provide integration\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/wordpress-form.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":306672,"url":"https:\/\/css-tricks.com\/using-formik-to-handle-forms-in-react\/","url_meta":{"origin":256018,"position":3},"title":"Using Formik to Handle Forms in React","date":"April 28, 2020","format":false,"excerpt":"There is no doubt that web forms play an integral role in our web site or applications. By default, they provide a useful set of elements and features \u2014 from legends and fieldsets to native validation and states \u2014 but they only get us so far when we start to\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/04\/formik-react.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":326533,"url":"https:\/\/css-tricks.com\/happier-html5-form-validation-in-vue\/","url_meta":{"origin":256018,"position":4},"title":"Happier HTML5 form validation in Vue","date":"December 3, 2020","format":false,"excerpt":"It's kind of neat that we can do input:invalid {} in CSS to style an input when it's in an invalid state. Yet, used exactly like that, the UX is pretty bad. Say you have . That's immediately invalid before the user has done anything. That's such a\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2017\/08\/forms-guide.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":248984,"url":"https:\/\/css-tricks.com\/webkit-now-html-interactive-form-validation\/","url_meta":{"origin":256018,"position":5},"title":"[WebKit now has] HTML Interactive Form Validation","date":"December 14, 2016","format":false,"excerpt":"Chris Dumez: WebKit did not support HTML interactive form validation, which occurs on form submission (unless the novalidate attribute is set on the element) or using the reportValidity() API. We are pleased to announce that this is now implemented in WebKit and enabled in Safari Technology Preview 19. Upon interactive\u2026","rel":"","context":"In "Link"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/256018"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/249049"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=256018"}],"version-history":[{"count":17,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/256018\/revisions"}],"predecessor-version":[{"id":256262,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/256018\/revisions\/256262"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=256018"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=256018"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=256018"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}